Using different kind of tools to build big styles for websites. Problem with big CSS is that it gets heavy, hard to manage, convoluted. But fortunately there are ways to keep structured and manageable. In this presentation we introduce combination of Makefile, SASS, ImageMagick, and other tools.
4. What we will learn
Description Tools and methods
Style Preprocessor SASS
Style speed Selector matching and specificity
Structuring the Style Split and join Style files
Style building automation Makefile
Automatic Image processing ImageMagick
Multiple layouts Makefile, SASS, ImageMagick
5. When your Style gets too fat
● Repeating and
dependent values
● Style too slow
● Files too big
http://www.waltsense.com/home/2010/4/23/too-fat-to-fight.html
6. When your theme gets too heavy
● Loss of overview
● Lack of structure
● Hard to manage http://benhartnett.com.au/artworkandplay/2009/hard-walking/
8. The problem and the solution
The problem
● A specific value used
for many times.
Example: main style
color.
● A specific value used
to derive other valus.
Example: calculation of
spacing values
The solution
Preprocessor
Example: Sass
13. The problem and the solution
The problem
Big style ruleset makes
page rendering slow in a
browser.
Symptom: browser hangs
for a moment before
displaying a page
The solution
Learn how selector
matching works:
● speed
● selectivity
14. Speed: Selector matching examples
#main-navigation { } /* ID (Fastest) */
body.home #page-wrap { } /* ID */
.main-navigation { } /* Class */
ul li a.current { } /* Class *
ul { } /* Tag */
ul li a { } /* Tag */
* { } /* Universal (Slowest) */
#content [title='home'] /* Universal */
#main-nav > li { } /* Slower than it might seem */
ul#main-navigation { } /* Don't */
html body ul li a { } /* Worst */
http://css-tricks.com/efficiently-rendering-css/
15. Speed: Selector matching rules
● Matching happens from right to left
● Failing rules are quicker than matching rules
● Google: css selector speed
16. Specificity: Calculation
A selector's specificity is calculated as follows:
● count the number of ID selectors in the selector (= a)
● count the number of class selectors, attributes selectors,
and pseudo-classes in the selector (= b)
● count the number of type selectors and pseudo-elements
in the selector (= c)
● ignore the universal selector
Concatenating the three numbers a-b-c (in a number system
with a large base) gives the specificity.
http://www.w3.org/TR/css3-selectors/#specificity
18. Example: classes for Views grid
<div class=”my-grid”>
<table>
<tr class=”my-grid-tr”>
<td class=”my-grid-td”> … </td>
<td class=”my-grid-td”> … </td>
</tr>
</table>
</div>
● This is simplification
● Only most relevant bits are shown
● Default classes are stripped to minimum
● Only custom classes are used for theming
20. Symptoms
* Convoluted code* Convoluted code
* Hard to keep track* Hard to keep track
* Hard to manage* Hard to manage
* Loss of overview* Loss of overview
* Hard to read :)* Hard to read :)
22. Structuring the Style
● Definitions file
● Elements
● Structural
● Fields
● Views
● Nodes
● Pages
23. Definitions file
● Path(s)
for example:
/sites/www.example.com/files/
● Image style dimensions
matches Drupal
Configuration > Image Styles
● Image dimensions
generated from actual images
● Dimensions
Like margins, certain element widths,
different layout sizes, etc
● Colors
custom color definitions
● CSS snippets
reusable CSS code like rounded()
● Included by all other
.sass files.
● Concatenated from
pieces.
27. What is a Makefile
● Utility “make” and rules file “Makefile” are
used to do automation
● Makefile specifies rules how to make target
files and what files does it depend on
● If dependency file is newer, the target will be
remade
29. Example 1/2: variables
# Assign individual files to variables
GLOBAL = global.css
DEFS = include/defs.sass
# The variable “ELEMENTS” is assigned list of files
# with directory and without suffixes
ELEMENTS = $(addprefix elements/,
tags
admin-menu
…
feedback
)
# same for other piece-sets
STRUCTURAL = $(addprefix structural/, … )
FIELDS = $(addprefix fields/, … )
VIEWS = $(addprefix views/, … )
NODES = $(addprefix nodes/, … )
PAGES = $(addprefix pages/, … )
# all pieces
PIECES = $(ELEMENTS) $(STRUCTURAL) $(FIELDS) $(VIEWS) $(NODES) $(PAGES)
# append .css
PIECES_CSS = $(addsuffix .css, $(PIECES))
30. Example 2/2: rules
# rule to generate final .css
# target depends on all .css pieces
# if any .css is missing it will be generated
# if any .css is newer than target, then the target will be regenerated
$(GLOBAL): $(PIECES_CSS)
cat $^ > $@
# rule to compile arbitrary .sass to .css
# if any required .css is missing it will be generated from
corresponding .sass file
# if any required .css is older than corresponding .sass it will be
regenerated
%.css: %.sass
sass $< $@
# any piece .css file depends on Makefile and definitions file
# if something is changed in Makefile or in definitions
# then all required .css files will be recompiled
$(PIECES_CSS): Makefile $(DEFS)
# kill all generated stuff
clean:
rm -f $(PIECES_CSS) $(GLOBAL)
find . -name '.sass-cache' -type d -print0 | xargs -0 rm -rf
31. Automatic variables
$@
The file name of the target of the rule. ‘$@’ is the name of whichever target caused the
rule's recipe to be run.
$<
The name of the first prerequisite.
$^
The names of all the prerequisites, with spaces between them.
$*
The stem with which an implicit rule matches. In a static pattern rule, the stem is part
of the file name that matched the ‘%’ in the target pattern.
http://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
32. Execution
● Clean up all stuff from previous compilation (rarely)
shell> make clean
rm -f elements/tags.css elements/admin-menu.css
elements/feedback.css structural/a.css … global.css
find . -name '.sass-cache' -type d -print0 | xargs -0 rm -rf
● Compile your theme (constantly)
shell> make
sass elements/tags.sass elements/tags.css
sass elements/admin-menu.sass elements/admin-menu.css
sass elements/feedback.sass elements/feedback.css
sass structural/a.sass structural/a.css
…
cat elements/tags.css elements/admin-menu.css
elements/feedback.css structural/a.css … > global.css
33. Explanation
● The example above describes a way to
compile one big .css file from multitude
of .sass files. Executed by 'make'.
● It knows exactly the dependency tree and
(re)generates all necessary files when
needed.
● It has instruction how to clean up all
generated files. Executed by 'make clean'.
35. What we need
● SASS handling for environment variables
● Tool to extract image dimensions for SASS
● Image conversion
● Layout styling to individual pieces
● Layout settings to definitions file
● Layout handling to Makefile
36. Environment variables for SASS
● Create file lib/env.rb as module/plugin/lib for SASS
module Sass::Script::Functions
def env(var)
assert_type var, :String
Sass::Script::String.new(ENV[var.to_s()])
end
end
● Using the module/plugin/lib
sass … --require lib/env.rb …
37. Automated image operations
ImageMagick® is free software
suite to create, edit, compose, or
convert bitmap images.
convert – convert between image
formats as well as resize an image,
blur, crop, despeckle, dither, draw
on, flip, join, re-sample, and much
more.
identify – describe the format and
characteristics of one or more image
files.
41. Image conversion
LOGO = logo.png
PNG =
logo-wide
logo-normal
logo-narrow
DERIVATIVES = $(addsuffix .png, $(PNG))
DIMENSIONS = $(addsuffix .sass, $(PNG))
all: $(DERIVATIVES) $(DIMENSIONS)
logo-wide.png: $(LOGO)
convert $< -geometry 200x $@
logo-normal.png: $(LOGO)
convert $< -geometry 150x $@
logo-narrow.png: $(LOGO)
convert $< -geometry 100x $@
$(DERIVATIVES): Makefile
%.sass: %.png
./wh $< > $@
clean:
rm -f $(DERIVATIVES) $(DIMENSIONS)
● In image directory there is
separate Makefile.
● It deals with automatic image
conversion for different
layouts.
● Executed by 'make'.
● In this particular example
logo.png is resized for 3
different layouts.
● In addition dimensions will be
extracted for these images for
SASS inclusion.
● Should the designer change
the logo, possibly even
changing its dimensions,
'make' will handle that.
42. Layout styling to individual pieces
@import "includes/defs.sass"
@if $LAYOUT == "global"
@if $LAYOUT == "alpha-default"
#logo
display: block
background-position: center
background-repeat: no-repeat
@if $LAYOUT == "alpha-default-narrow"
#logo
width: $WIDTH_LOGO_NARROW
height: $HEIGHT_LOGO_NARROW
background-image: url($IMG + "logo-narrow.png")
@if $LAYOUT == "alpha-default-normal"
#logo
width: $WIDTH_LOGO_NORMAL
height: $HEIGHT_LOGO_NORMAL
background-image: url($IMG + "logo-normal.png")
@if $LAYOUT == "alpha-default-wide"
#logo
width: $WIDTH_LOGO_WIDE
height: $HEIGHT_LOGO_WIDE
background-image: url($IMG + "logo-wide.png")
● This SASS compiles into 4 CSS
files according to “if” statement.
● It styles #logo element for different
layouts.
● It uses the logo image's
dimensions which is set up
automatically.
● It uses $IMG to save you from
carpal tunnel syndrome.
43. Layout settings to definitions file
● Common definitions file includes all image dimensions which are used in
any layout
● SASS variable LAYOUT will be assigned according to environment
variable LAYOUT:
$LAYOUT: env(LAYOUT)
● Layout-specific definitions
$SPACER: 0
@if $LAYOUT == "global"
@if $LAYOUT == "alpha-default"
@if $LAYOUT == "alpha-default-narrow"
$SPACER: 10px
@if $LAYOUT == "alpha-default-normal"
$SPACER: 15px
@if $LAYOUT == "alpha-default-wide"
$SPACER: 20px
This SASS code assigns layout-
dependent value(s) to variable(s).
45. Layout handling to Makefile
TARGET = $(LAYOUT).css
LAYOUTS =
global
alpha-default
alpha-default-narrow
alpha-default-normal
alpha-default-wide
PIECES_CSS = $(addsuffix .$(LAYOUT).css, $(PIECES))
all:
for layout in $(LAYOUTS); do
make $$layout.css -e LAYOUT=$$layout
|| exit 1 ;
done
$(TARGET): $(PIECES_CSS)
cat $^ > $@
%.$(LAYOUT).css: %.sass
LAYOUT=$(LAYOUT)
sass --require lib/env.rb $< $@
$(PIECES_CSS): Makefile $(DEFS)
clean:
for layout in $(LAYOUTS); do
make clean-$$layout -e LAYOUT=$$layout
|| exit 1 ;
done
clean-$(LAYOUT):
rm -f $(PIECES_CSS)
rm -f $(TARGET)
● This Makefile is not complete
● It is extension to earlier one
● This Makefile works by using environment
variable LAYOUT
● This makefile works by executing itself in
different context (env LAYOUT value).
● The environment variable LAYOUT is
available as Makefile variable $(LAYOUT)
● This Makefile produces one stylesheet for
each layout named as layout.css
● Each layout.css is concatenation of css
pieces named as name.layout.css which
are compiled from name.sass
46. Difference between
the easy way and the hard way
● Speed difference ca 10x
● If (easy_way.compile() == too_slow)
then goto hard_way;
● Remember that during theming process
compilation is very frequent procedure
47. What did we learn
Description Tools and methods
Style Preprocessor SASS
Style speed Selector matching and specificity
Structuring the Style Split and join Style files
Style building automation Make / Makefile
Automatic Image processing ImageMagick
Multiple layouts Make / Makefile, SASS, ImageMagick