Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to be a Super CSS Detective

How to be a Super CSS Detective

A look at some advanced CSS investigative and problem-solving techniques, including tiny tidbits to lay the foundation for clean, informative markup; ways of dealing definitively with IE6/7, proactive coding practices for the “other” browsers’ bugs, new alternatives to using floats for layout, and creating and using the more esoteric css2 selectors and newer css3 selectors for true style targeting power. Presented at FITC Toronto, April 2012.

Avatar for denisejacobs

denisejacobs

April 25, 2012
Tweet

Other Decks in Technology

Transcript

  1. or How to Become a Super CSS Detective in 4

    Easy Steps Denise R. Jacobs @ FITC Toronto 2012 25 April 2012 Advanced CSS Advanced CSS Troubleshooting & Efficiency Troubleshooting & Efficiency
  2. 10 Whodunnit? I did! I’m an author, web designer, speaker

    and trainer, and creativity evangelist. I wrote The CSS Detective Guide, and co-authored InterAct with Web Standards as well as the upcoming Smashing Book #3. I’ve contributed articles to NetMagazine and A List Apart.
  3. 11 CSS De-what? • Preventive/defensive coding – Focused & efficient

    • Can quickly and easily identify and solve problems when they come up http://www.flickr.com/photos/spotrick/4028499019/
  4. 12 I can haz trubbleshootin? Strong troubleshooting skills are one

    of your best allies in solving CSS “mysteries”…and they also make you feel like a badass.
  5. 21 SO... It’s a constant reminder: It’s still important to

    have the basics in place! So, let’s look at…
  6. 22 The 4 Easy Steps 1) Lay the foundation 2)

    Target your styles 3) Squash browser bugs 4) Employ useful tools
  7. 24 Why? A solid CSS foundation of best practices creates

    an environment where preventing and detecting problems is easier.
  8. 25 The Foundations 1. Set a Baseline 2. Micro-Optimize 3.

    Macro-Optimize 4. Clear Float Issues
  9. 27 Foundation 1: Create a Baseline 1. The CSS Reset

    All-star 2. DIY Resets 3. CSS Reset Compendia
  10. 28 Why Reset? By deliberately establishing an element’s properties, you

    can: • Better control the elements on the page • More quickly determine the source of problems when they arise • Ensure better cross-browser compatibility
  11. 29 CSS Reset All-Star: Eric Meyer’s Pro’s – One of

    the most popular, well thought-out – Neutralizes almost every element Con’s – Can be too far-reaching – Extra work to establish the values for the elements you want
  12. 32 DIY Resets • You can determine exactly which elements

    you want to reset • May save on reestablishing properties • You know exactly what is changed and why you changed it • Problems will be that much more obvious
  13. 33 Top Properties to Reset • Margin and padding •

    Borders, especially on linked images • Link text underlining • Vertical alignment • Font size and line-height
  14. 35 Resource: CSS Reset Compendia Killer Collection of CSS Resets

    http://tinyurl.com/5bdoj2 More Killer CSS Resets http://tinyurl.com/n746dl
  15. 37 Normalize v. Reset Normalize.css preserves useful defaults • Resets

    impose a homogenous visual style by flattening the default styles for almost all elements. In contrast, normalize.css retains many useful default browser styles. This means that you don’t have to redeclare styles for all the common typographic elements. • When an element has different default styles in different browsers, normalize.css aims to make those styles consistent and in line with modern standards when possible. • Normalize.css corrects common bugs • It fixes common desktop and mobile browser bugs that are out of scope for resets. This includes display settings for HTML5 elements, correcting font-size for preformatted text, SVG overflow in IE9, and many form-related bugs across browsers and operating systems.
  16. 39 Why Micro-Optimize? • Cuts down file size • Speeds

    up page load time • Encourages best practices
  17. 41 Micro-optimize: Alphabetize Putting your CSS declarations in alphabetical order

    is a great way to set the stage for clean code and fewer problems. Why? Because your style declarations will be that much easier to target and locate.
  18. 42 Find “width” - which is easier? Example One: .login

    { margin-top: 5px; line-height: 1.5em; padding-left: 5px; float: right; list-style-type: none; width: 80px; font-weight: bold; border-left: 1px solid #69824d; } Example Two: .login { border-left: 1px solid #69824d; float: right; font-weight: bold; line-height: 1.5em; list-style-type: none; margin-top: 5px; padding-left: 5px; width: 80px; }
  19. 43 Find “width” - which is easier? Example One: .login

    { margin-top: 5px; line-height: 1.5em; padding-left: 5px; float: right; list-style-type: none; width: 80px; font-weight: bold; border-left: 1px solid #69824d; } Example Two: .login { border-left: 1px solid #69824d; float: right; font-weight: bold; line-height: 1.5em; list-style-type: none; margin-top: 5px; padding-left: 5px; width: 80px; }
  20. 44 Micro-optimize: Speed Up the efficiency: • ID selectors are

    speedier than element or universal* • Drop element qualifiers • Ditch descendent selectors when and where you can *conflicts with reduce, reuse, & recycle, however
  21. 45 Micro-Optimization in Action Pre-optimization: #wrapper div#sidebar { background: #fff

    url(bg.png) repeat-x 0 0; border: 1px solid #ff0; font: normal 1.33em/1.33 Georgia, serif; margin: 10px 20px; padding: .1em; }
  22. 46 Micro-Optimization in Action Post-optimization : #sidebar { background: #fff

    url(bg.png) repeat-x 0 0; border: 1px solid #ff0; font: normal 1.33em/1.33 Georgia, serif; margin: 10px 20px; padding: .1em; }
  23. 47 Micro-Optimize Your CSS: Length Less is more: • Use

    shortest properties and values (shorthand) • Avoid duplicate properties • Condense values and units • Avoid multiple lines and indenting
  24. 48 Micro-Optimization in Action Example: #sidebar { background: #fff url(bg.png)

    repeat-x 0 0; border: 1px solid #ff0; font: normal 1.33em/1.33 Georgia, serif; margin: 10px 20px; padding: .1em; }
  25. 49 Shorthand: to remember • Default values • Shorthand property

    syntax • Required property values • Property value order
  26. 50 Micro-Optimize: Length Less is more: • Use shortest properties

    and values (shorthand) • Avoid duplicate properties • Condense values and units • Avoid multiple lines and indenting
  27. 51 Micro-Optimization in Action Example: #sidebar { background: #fff url(bg.png)

    repeat-x 0 0; border: 1px solid #ff0; font: normal 1.33em/1.33 Georgia, serif; margin: 10px 20px; padding: .1em; }
  28. 52 Micro-Optimize: Length Less is more: • Use shortest properties

    and values (shorthand) • Avoid duplicate properties • Condense values and units • Avoid multiple lines and indenting
  29. 53 Micro-Optimization in Action Example: #sidebar { background: #fff url(bg.png)

    repeat-x 0 0; border: 1px solid red; font: normal 1.33em/1.33 Georgia, serif; margin: 10px 20px; padding: .1em; }
  30. 54 Micro-Optimize: Length Less is more: • Use shortest properties

    and values (shorthand) • Avoid duplicate properties • Condense values and units • Avoid multiple lines and indenting
  31. 58 Why Macro-Optimize? Solo: Helps you remember your intentions when

    you come back to your code. With others: Helps your colleagues understand your intentions when working with your code. Ergo: Saves time!
  32. 61 Why get your nest in order? Block-level elements inside

    inline elements as well as improper closing and reopening of elements can create major layout issues. Validation often won’t help you find the culprit.
  33. 62 Macro-optimize: Get your nest in order <body> <div id="pagewrap">

    <div id="header"> <h1>Website Title</h1> <ul id="navigation"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> <div id="contentwrap"> <div id="maincontent"> <h2>Main Content Title</h2> <p>Main content, which is so much more important than the secondary content that it makes one teary with emotion.</p> </div> <div id="secondarycontent"> <h3>Sidebar Title</h3> <p>Sidebar content, which is not as important as the primary content (which is why it is in the sidebar)</p> </div> <div id="footer"> <p>standard copyright and footer information</p> </div> </body> <body> <div id="pagewrap"> <div id="header"> <h1>Website Title</h1> <ul id="navigation"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> </div><!-- end #header --> <div id="contentwrap"> <div id="maincontent"> <h2>Main Content Title</h2> <p>Main content, which is so much more important than the secondary content that it makes one teary with emotion.</p> </div><!-- end #maincontent --> <div id="secondarycontent"> <h3>Sidebar Title</h3> <p>Sidebar content, which is not as important as the primary content (which is why it is in the sidebar)</p> </div><!-- end #secondarycontent --> </div><!-- end #cotentwrap --> <div id="footer"> <p>standard copyright and footer information</p> </div><!-- end #footer --> </div><!-- end #pagewrap --> </body>
  34. 64 Why Annotate Your Code? Markup: Helps you keep track

    of the element beginning and end, and helps you identify the pieces faster. CSS: Helps both you and others know intentions and specific information.
  35. 65 Macro-optimize: Annotate Your Markup begin with <!-- #id or

    .class name --> end with <!-- /end #id or .class name --> or, alternatively <!-- / #id or .class name -->
  36. 66 Macro-optimize: Annotate Your Markup Example: <div id="content"> <div class="promo">

    ... </div><!-- /end .promo --> </div><!-- /end #content -->
  37. 67 Macro-optimize: Annotate Your CSS /* Comments are good, mmkay?

    */ Notation is your friend. For: • Overriding styles • Creating stylesheet sections • Listing the color scheme • Resources and contact info.
  38. 68 Macro-optimize: Annotate Your CSS /* made by you on

    some date */ /* section of the stylesheet */ p { border-color: #cf0; border-color-bottom: #ccc; /*this property overrides the previous one */ }
  39. 70 Why Reduce, Reuse, & Recycle? • Cuts down file

    size • Speeds up page load time • Encourages best practices
  40. 71 Macro-optimize: Reduce • Identify content patterns • Use classes

    instead of ids & elements • Define defaults
  41. 72 Macro-optimize: Reduce • Identify content patterns • Use classes

    instead of ids & elements • Define defaults
  42. 73 Classes, not IDs <ul id="navmain"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li>

    <li><a href="#">Contact</a></li> </ul> <ul class="nav"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul>
  43. 74 Macro-optimize: Reduce • Identify content patterns • Use classes

    instead of ids & elements • Define defaults
  44. 75 Define Defaults Not this: #maincontent h1 {...} #maincontent #callout

    h2 {...} But rather this: h1, .h1 {...} h2, .h2 {...}
  45. 77 Leverage the Cascade Not this: html body .nav .hd

    {...} or .headerofheadsectio nofpage {...} Instead this: .nav .hd {...}
  46. 81 Class-combining html <ul id="navmain"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a

    href="#">Contact</a></li> </ul> <ul id="navfoot"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> css #navmain { (other styles); background-color: green;} #navfoot { (other styles); background-color: black;} html <ul class="nav main"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> <ul class="nav foot"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> css .nav {(other styles);} .main {background-color: green;} .foot {background-color: black;}
  47. 85 Why? Floats are the primary basis for tableless layouts,

    so knowing how to manage them is critical.* *there are, however, alternatives, which we’ll talk about in a little bit.
  48. 86 Containing floats Because floats are taken out of the

    flow, they are not contained by their parent element unless the parent contains an element that is cleared. Otherwise the parent will collapse.
  49. 87 Clear Float Issues 1) Problems with overflow: hidden 2)

    Problems with Clearfix 3) Solutions and Alternatives
  50. 89 Floats: overflow: hidden Issues Although this is almost everyone’s

    favorite float- clearing technique, there can be problems with: • Hiding content with no scrollbars when browser window is smaller than container • Interference with margins, borders, outlines, and absolutely-positioned PNGs • Application of CSS3 properties, such as ƒ box-shadow, ƒ text-shadow ƒ transform
  51. 90 Reminder: overflow: visible overflow: visible allows the content to

    be rendered regardless of the element box’s dimensions.
  52. 91 Reminder: overflow: scroll overflow: scroll, the browser creates scrollbars

    to let the user view the content of the element while maintaining the specified dimensions.
  53. 92 Reminder: overflow: auto overflow: auto lets the browser determine

    whether scrollbars are needed, and will only create them if and where necessary.
  54. 93 Reminder: overflow: hidden overflow: hidden makes the content in

    the element box to disappear if it extends past the boundaries of the box.
  55. 95 overflow: hidden Improved Example: .container { border: 1px solid

    #000000; overflow: auto; /* hidden & scroll also work*/ width: 100%; /* some width or height required */ }
  56. 97 ClearfixIssues 1. Remember where to put it: Apply .clearfix

    to the element containing the floats, so that the cleared content is generated after the content inside of it. 2. Be aware of support: Neither IE6 nor IE7 support the :after pseudo- class, so a trigger of hasLayout is necessary.
  57. 98 ClearfixIssues 3. Be mindful of the generated content: Sometimes

    the generated period can be a problem. 4. Be aware of collapsing margins: New clearfixes speak to this.
  58. 99 Reminder: display: block & inline-block Block: With display: block

    an element will display as a block element, with whitespace above and below it, and no elements next to it. Inline-block: With display: inline-block, an element can have a width assigned to it like a block element, while still appearing the in the horizontal flow with its surrounding inline elements. VS.
  59. 100 The New Clearfix .clearfix:after { clear: both; content: "

    "; display: block; font-size: 0; height: 0; visibility: hidden; } *html .clearfix {zoom: 1;} /* IE6 */ *:first-child+html .clearfix {zoom: 1;} /* IE7 */ http://perishablepress.com/press/2009/12/06/new-clearfix-hack/
  60. 101 Clearfix Reloaded .clearfix:before, .clearfix:after { content: "."; display: block;

    height: 0; overflow: hidden; } .clearfix:after {clear: both;} .clearfix {zoom: 1;} /* IE < 8 */ http://www.yuiblog.com/blog/2010/09/27/clearfix-reloaded-overflowhidden-demystified/
  61. 102 The Magnificent Clearfix .clearfix:before, .clearfix:after { content: "\0020"; /*this

    is a space*/ display: block; height: 0; visibility: hidden; } .clearfix:after {clear: both;} .clearfix { zoom: 1; } /* IE fix for extra margin at bottom of page */ http://html5boilerplate.com/ (circa 2010)
  62. 103 Micro Clearfix /* For modern browsers */ .cf:before, .cf:after

    { content:""; display:table; } .cf:after {clear:both;} .cf {zoom:1;} /* For IE 6/7 (triggers hasLayout) */ http://nicolasgallagher.com/micro-clearfix-hack/ and http://html5boilerplate.com/
  63. 104 Why So Freakin’Many??!! Most differences/improvements try to address •

    hasLayout in IE lt 7 • margin collapse in multiple browsers. – Both top and bottom (which is why :before and :after are used)
  64. 107 Float Nearly Everything FnE still a viable option: •

    Contains and clears Potential issue: • Watch for how it affects the rest of the page layout and structure
  65. 109 overflow: hidden Alternative If you can apply a width

    to the element containing floats, then another option is to use: .container { display: inline-block; width: <any explicit value>; } http://www.yuiblog.com/blog/2010/09/27/clearfix-reloaded-overflowhidden-demystified/
  66. 110 Reminder: display: block & inline-block Block: With display: block

    an element will display as a block element, with whitespace above and below it, and no elements next to it. Inline-block: With display: inline-block, an element can have a width assigned to it like a block element, while still appearing the in the horizontal flow with its surrounding inline elements.
  67. 111 Future Hope For Page Layouts CSS3 and HTML5 FTW!

    CSS3: flexible box-model and box-sizing (columns best for text only) HTML5 Semantics: <header>,<section>, <aside>,<footer>,etc.
  68. 113 Why? Having a plan for targeting elements helps speed

    and efficiency – in both creating and fixing styles.
  69. 116 My Fave Targeting Technique outline: 1px solid red; Why?

    • outline does not add to dimensions of the element • Color names used only for troubleshooting
  70. 118 My Fave Testing Technique Indent trial styles: .searchform >

    .searchsubmit { width: 14%; height: 25px; background: transparent url(images/icon_magnify.png) 0 0 no- repeat; margin: -2px 0 0 0; } Why? •You know for sure that the style is temporary and it’s easy to scan and find for later
  71. 120 My Fave Disabling Technique “X” out styles: .social li

    a { -moz-transition: opacity 0.3s ease 0s; x-display: block; height: 35px; opacity: 0.4; } Why? •Easier than commenting out, you keep the style for later, and it’s easy to scan and find.
  72. 122 Specificity Rules! Using selective specificity, you can create selectors

    that will zero in on your desired element(s), but you’ve got to do it by the rules.
  73. 124 Super-Simplified Specificity The more specific the selector is, the

    higher the specificity #id: can only be one on the page = high specificity (100) .class: can be multiple, but not everywhere = medium specificity (10) element: lots on the page = low specificity (1) * : everything on the page = no specificity (0)
  74. 126 Specificity Best Practices • Don’t rely too heavily on

    specificity – leverage as many reusable selectors as possible • Use the cascade and source order so that you don’t have to get too specific • Trust specificity over source order in terms of which style will win and get applied
  75. 128 Getting Advanced Advanced selectors are a good way to

    specifically target styles for modern browsers. The right selector will help you achieve targeting nirvana, so it’s important to know which selectors you can use now.
  76. 129 Uses for advanced selectors • Great for progressive enhancement

    • Styling first, last or x-number of elements • Styling generated content
  77. 130 Let’s peek at 1. CSS2 Selectors • browser support

    2. CSS3 Selectors • browser support
  78. 131 Advanced Selectors: Usage Tips • All of the CSS2

    selectors are supported by the modern browsers, and almost all of the CSS3 ones are, so use them! • It’s easy to target styles away from the IEs, but target them to the IEs with simpler combinator selectors
  79. 133 CSS 2.1 Selectors • Universal * • Child Combinator

    E > F • Adjacent/Sibling Combinator E + F • Attribute E[~attribute] • At Rules – @font-face – @media – @page – @charset • Pseudo elements – :before – :after • State pseudo-classes – Dynamic • :hover • :active • :focus – Language • :lang – Structural • :first-child
  80. 134 CSS2.1 Selectors & IE Support • Universal * (ie7/8

    – yes) • Child: e > f (ie7/8 – yes) • Sibling/Adjacent: e + f (ie7 no, ie8 – yes) • Attribute: e[attribute] (ie7/8 – yes) • Pseudo elements (ie7/8 – no) – ::before – ::after • State pseudo-classes, v2.1 – :first-child (ie7/8 – yes) – :hover (ie7/8 – yes) – :active (ie7/8 – yes) – :focus (ie7/8 – no) – :lang (ie7/8 – no)
  81. 137 CSS3 Selectors • General sibling E ~ F •

    Attribute presence – a[attribute="value"] – a[attribute~="value"] – a[attribute|="value"] • Attribute substrings – a[attribute^="value"] – a[attribute$="value"] – a[attribute*="value"] • Pseudo-elements* *all pseudo-elements indicated with :: in CSS3
  82. 138 CSS3 Selectors (cont’d) • Pseudo-classes – Target • :target

    – Negation • :not(s) – State • :enabled • :disabled • :checked • :indeterminate – Structural • :nth-child(n) • :nth-last-child(n) • :nth-of-type(n) • :nth-last-of-type(n) • :last-child • :first-of-type • :last-of-type • :only-child • :only-of-type • :empty
  83. 143 Gettin’ Buggy With It Despite your best efforts towards

    clean, efficient, optimized code, browsers will always have issues that throw a wrench in the works.
  84. 145 Achieving Cross-browser Compatibility 1. Decide on your approach to

    deal with IE6 2. Target other browsers 3. Know IE 7 & IE 8 bugs 4. Know Firefox bugs 5. Know Webkit bugs 6. Know Opera bugs
  85. 147 Dealing with IE6 (Still? Yes, still.) Whether it’s by

    force or by choice, you need to know how you are going to deal with IE6 until it’s completely gone.
  86. 149 Approaches for IE6 Options: • Kick it to the

    curb • Display tolerant indifference • Show some love: be graceful in your degradation
  87. 152 Kicked: IE6, I just won’t support you. In IE6

    In modern browsers paulcarbo.net
  88. 160 Graceful IE6 Degradation • Serve IE6 targeted properties with

    conditional comments – display: inline – zoom: 1 • Use the * html hack
  89. 165 Other browser hacks There are “hacks” to target styles

    to specific browsers, other than the IEs if you really want to use them…
  90. 168 IE7 is color buggin’ color and background-color with rgba

    The problem: An rgba color is correctly set to override the rgb for the IEs , but the rgb color doesn’t show up at all.
  91. 169 IE7 is color buggin’ The solution: Use the shorthand

    property background instead of background-color OR Use a hexidecimal color instead of rgb, and then continue the override with rgba.
  92. 170 IE7 is color buggin’ Example: div { background: rgb(200,

    54, 54); /* fallback color */ background: rgba(200, 54, 54, 0.5); } OR div { background-color: #fd7e7e; background-color: rgba(255,0,0,0.5); }
  93. 171 IE7 & IE8 are both font buggin’ @font-face super

    bullet-proofing The problem: @font-face doesn’t work, even with the proper normal syntax. What gives?
  94. 172 Solution: IE7 & IE8 font issues Example: @font-face {

    font-family: 'MyFontFamily'; src: url('myfont-webfont.eot?#iefix‘) format('embedded-opentype'), url('myfont-webfont.woff') format('woff'), url('myfont- webfont.ttf')format('truetype'), url('myfont-webfont.svg#svgFontName') format('svg'); }
  95. 174 Get Your WebkitBug On @font-face bold and italics “bug”

    The problem: Applying font-weight: bold or font-style: italic to @font-face'd text doesn’t work.
  96. 175 Get Your Webkit Bug On The solution: Add the

    value normal to font weight, style, and variant in the @font-face declaration to set a baseline.
  97. 176 @font-face + faux variations Example: @font-face { font-family: 'MyFontFamily';

    src: url('myfont-webfont.eot?#iefix‘) format('embedded-opentype'), url('myfont-webfont.woff') format('woff'), url('myfont- webfont.ttf')format('truetype'), url('myfont-webfont.svg#svgFontName') format('svg'); font-weight:normal; font-style:normal; font-variant:normal; }
  98. 178 Firefox? Buggin’. The Outline Overflow Bug The problem: Firefox

    will draw an outline around the content of an element that has overflowed its boundaries rather than around the element’s actual set dimensions.
  99. 181 Firefox? Buggin’. The Outline Overflow Bug A possible solution:

    Use border instead and adjust the dimensions of the element. ??? Open for suggestions!!!
  100. 183 An Ode to Opera Bugs Hiding elements bug The

    problem: When hiding elements offscreen for image replacement, etc. em units are not recognized.
  101. 184 An Ode to Opera Bugs The solution: Use px

    instead of em Example: h2 {margin-left: -4999px;}
  102. 185 The Hotness: Latest IR technique <style> <h1>This Text is

    Replaced</h1> </style> instead of: h1 { background: url("myimage") 0 0 no-repeat; text-indent:-9999px; } use: .replace { text-indent: 100%; white-space: nowrap; overflow: hidden; } http://www.sitepoint.com/new-css-image-replacement-technique/
  103. 187 Tools rock Having a strong arsenal of tools helps

    with workflow, removes guesswork, and makes life a ton easier.
  104. 189 Reference: CSS Specifications The CSS3 Specifications are THE resource

    for finding out the exact intended behavior and use of any given property. http://www.w3.org/standards/ techs/css#w3c_all
  105. 204 Resources: Front-End Best Practices “Isobar's Front-end Code Standards &

    Best Practices” “A Crash Course in the HTML5/CSS3/JS Techniques of the Modern Front-End Maestro”
  106. 205 Recap Taking all of these steps: 1. Lay the

    foundation 2. Target your styles 3. Squash browser bugs 4. Employ powerful tools Will yield: 1. Code that is easier to read and find problems in 2. Finding solutions faster 3. Speed of use and in use
  107. 212 Smashing Books #3 & #3 1/3 My chapter: “Storytelling

    in Webdesign” Redesign from all angles
  108. 213 InterAct With Web Standards: A Holistic Approach to Web

    Design InterActWithWebStandards.com twitter.com/waspinteract Web design, served up holistically