Compile your Style
Upcoming SlideShare
Loading in...5

Compile your Style



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 ...

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.



Total Views
Views on SlideShare
Embed Views



0 Embeds 0

No embeds



Upload Details

Uploaded via as OpenOffice

Usage Rights

CC Attribution License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
Post Comment
Edit your comment

Compile your Style Compile your Style Presentation Transcript

  • Ragnar Kurm | DrupalCamp Baltics Estonia, Tallinn | 2013 Compile your Style
  • Ragnar Kurm ● 25 years of programming ● 5 years of Drupal ● 30 Drupal sites ● 1 big & busy community site
  • Audients ● Those who build a big theme(s) ● Those who are specialized on theming
  • 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
  • When your Style gets too fat ● Repeating and dependent values ● Style too slow ● Files too big
  • When your theme gets too heavy ● Loss of overview ● Lack of structure ● Hard to manage
  • Repeating and dependent values
  • 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
  • Example SASS $blue: #3bbfce $space: 16px .one, .two padding: $space / 2 p color: darken($blue, 9%) CSS .one, .two { padding: 8px; } .one p, .two p { color: #2b9eab; }
  • Usage shell> sass global.sass global.css This compiles a .sass file into a .css file.
  • More about Preprocessor ● Numbers, colors, strings ● Variables ● Calculations ● Conditions ● Functions and arguments ● Style reuse ● File inclusion
  • Speed of the Style
  • 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
  • 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 */
  • Speed: Selector matching rules ● Matching happens from right to left ● Failing rules are quicker than matching rules ● Google: css selector speed
  • 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.
  • Specificity: Examples * /* a=0 b=0 c=0 -> specificity = 0 */ LI /* a=0 b=0 c=1 -> specificity = 1 */ UL LI /* a=0 b=0 c=2 -> specificity = 2 */ UL OL+LI /* a=0 b=0 c=3 -> specificity = 3 */ H1 + *[REL=up] /* a=0 b=1 c=1 -> specificity = 11 */ UL OL /* a=0 b=1 c=3 -> specificity = 13 */ /* a=0 b=2 c=1 -> specificity = 21 */ #x34y /* a=1 b=0 c=0 -> specificity = 100 */ #s12:not(FOO) /* a=1 b=0 c=1 -> specificity = 101 */
  • 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
  • Too big Style files
  • 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 :)
  • Solution ● Structuring: Split and join ● Use automation: Makefile
  • Structuring the Style ● Definitions file ● Elements ● Structural ● Fields ● Views ● Nodes ● Pages
  • Definitions file ● Path(s) for example: /sites/ ● 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.
  • CSS Pieces ● Elements / – General tags – Pager ● Structural / – Zones – Zone-header – Zone-footer – Regions – Regions-header-first – Regions-footer-first – Blocks – Block-main-menu ● Fields / – Forms – Type-display – Type-form – Type-boolean-display – Type-boolean-form – Field-like-display – Field-like-form ● Views / – Views – My-grid – My-table – Product-list – Member-list ● Nodes / – Node – Book – Article ● Pages / – Front – Contact – Node-add
  • Join the Pieces The easy way ● Include all pieces together (example: a.sass) @import "includes/defs.sass" @import "elements/admin-menu.sass" @import "elements/ads.sass" @import "elements/feedback.sass" @import "elements/help.sass" @import "elements/image.sass" @import "elements/system.messages.sass" … ● Compile the file sass a.sass a.css
  • Automation: The Makefile The hard way Tesla factory in Fremont, California
  • 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
  • Automatics schematics global.css piece3.css piece2.css piece1.css piece3.sass piece2.sass piece1.sass
  • 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))
  • 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
  • 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.
  • 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
  • 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'.
  • Multiple layouts Drupal theme Seven
  • 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
  • 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[var.to_s()]) end end ● Using the module/plugin/lib sass … --require lib/env.rb …
  • 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.
  • ImageMagick one-liners
  • Image dimensions for SASS ● Shell script that extracts image dimensions shell> cat ./wh #!/bin/sh img="$1" label=`echo "$img" | tr 'a-z-' 'A-Z_' | sed 's/.[A-Z]*$//'` identify -format "$WIDTH_$label: %wpx" "$img" identify -format "$HEIGHT_$label: %hpx" "$img" ● Usage and output of the script shell> ./wh logo-big.png $WIDTH_LOGO_BIG: 100px $HEIGHT_LOGO_BIG: 50px
  • Image derivation schematics logo.png logo-wide.png logo-normal.png logo-narrow.png logo-wide.sass logo-normal.sass logo-narrow.sass
  • 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.
  • 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.
  • 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).
  • Layout schematics global.css alpha-default.css piece1.alpha-default.css piece2.alpha-default.css piece1.sass piece2.sass
  • 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
  • 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
  • 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
  • Further reading Scalable and Modular Architecture for CSS