The Evolution of Selectors

Post on 16-Jul-2015

148 views 2 download

Transcript of The Evolution of Selectors

THE EVOLUTION OF SELECTORS - CSS Brigade - May 29, 2014Dave Arthur

OVERVIEW OF TALK1. Brief intro to how CSS evolves

2. Highlight some level 2/3 selectors

3. Look at some level 3/4 selectors

4. Talk about selector performance and maintenance

CSS IS CONSTANTLY EVOLVINGSelectors are now at Level 4. What does that mean?

Since CSS3, the spec is broken up into “modules”, each defining aspecific part of CSS. [Click image below to see live W3C page]

SELECTOR LEVELS

LEVEL 1ID, class, type/tag, descendantcombinator, :link, :visited,:active, :first-letter,:first-line

LEVEL 2Level 1 + universal(*), attribute,more combinators, :hover,:focus, :before, :after,:first-child

LEVEL 3Level 1 + 2 + structural pseudo-classes incl. :last-child and:nth-child(), UI pseudo-classes,negation (:not()) and :targetpseudo-classes

LEVEL 4Level 1 + 2 + 3 + more UI pseudo-classes, :matches(), :has(), timedimensional pseudo-classes (e.g.text to speech), link pseudo-classes,drag-and-drop-related pseudo-classes, grid-related pseudo-classes

LEVEL 2 SELECTOR HIGHLIGHTS

CHILD SELECTOR (COMBINATOR)X > Y

Instead of targeting all descendants of a particular container, itwill only target the direct children.

E.g.: Styling a nested news list

Transport Minister Lisa Raitt said electronicdevices can be used during takeoff, ascent,descent, landing.

Charlie Angus, Francoise Boivin warngovernment to tread carefully on internetprivacy.

Ottawa to allow air passengers to useelectronic devices on takeoff, landing

Flight attendants resist Transport Canada’s move to cut their numbers

Airline travel: 5 things you need to know about your flight rights

NDP wants privacy, security experts to probewarrantless data gathering

Declaration on mass surveillance calls for new privacy measures

Cyberbullying bill surveillance powers alarm Ontario privacy watchdog

<section class="news"> <ul class="news-list"> <li> <article class="article"> <h4 class="article-title"><a href="#"></a></h4> <figure class="article-thumb"><a href="#"><img></a></figure> <p class="article-desc"></p> <ul> <li><a href="#"></a></li> <li><a href="#"></a></li> </ul> </article> </li> <li> <article class="article"> <h4 class="article-title"><a href="#"></a></h4> <figure class="article-thumb"><a href="#"><img></a></figure> <p class="article-desc"></p> <ul> <li><a href="#"></a></li> <li><a href="#"></a></li> </ul> </article> </li> </ul></section>

Check out the for full HTMLCodePen

Using a descendant selector - over-rides needed:

.news-list li { /* Descendant */ list-style: none; padding: 0.5em; margin-bottom: 0.5em; border-bottom: 1px solid #d5d5d5;}

.article li { list-style: square; font-size: 0.9em; padding: 0; /* over-ride */ border-bottom: none; /* over-ride */}

Using a child selector - cleaner:

.news-list > li { /* Child selector - only selects top-level lis */ list-style: none; padding: 0.5em; border-bottom: 1px solid #d5d5d5;}

.news-list li { /* Descendant - common property in all lis (DRY) */ margin-bottom: 0.5em;}

.article li { list-style: square; font-size: 0.9em; /* no over-ride of bottom border or padding needed */}

Check out the for full CSSCodePen

ADJACENT SIBLING SELECTOR (COMBINATOR)

X + Y

Targets elements (Y) which have a particular element (X) direclypreceeding it.

E.g.: Simple inline menu with visual separators

• • •Home About Work Contact

<nav class="menu" role="navigation"> <ul class="menu-list"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Work</a></li> <li><a href="#">Contact</a></li> </ul></nav>

.menu-list > li:before { content: '\2022'; padding-right: 0.5em; margin-left: 0.5em; }.menu-list > li:first-child:before { content: none;}

Cleaner way using “+” combinator

<nav class="menu" role="navigation"> <ul class="menu-list"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Work</a></li> <li><a href="#">Contact</a></li> </ul></nav>

.menu-list > li + li:before { content: '\2022'; padding-right: 0.5em; margin-left: 0.5em; }

Check out the for exampleCodePen

ATTRIBUTE SELECTORS (LEVEL 2 & 3)elem[attr="value"] 2elem[attr̂="str"] 3elem[attr$="str"] 3elem[attr*="str"] 3

Full list of attribute selectors:http://dev.w3.org/csswg/selectors4/#attribute-selectors

elem[attr="value"]Since there are many different input element types (especiallywith HTML5) this selector is great for targeting specific types.

input[type="text"], input[type="email"] { border: 1px solid #999; padding: 5px 10px; }

input[type="submit"] { background-color: #0065BD; color: #fff; border-radius: 10px; padding: 10px; }

elem[attr̂="str"]Selects elements which have an attribute value beginning with a

particular substring.

E.g. Styling links with different URLs:

Contact us by: Secure Form Email

<section class="contact"> <h4>Contact us by:</h4> <a href="https://secure.domain.com/contact">Secure Form</a> <a href="mailto:contact@hello.com">Email</a></section>

.contact > a:before { font-family: 'icomoon'; /* other font declarations */ margin-right: 0.25em;}

.contact > a[href̂="https://secure.domain.com"]:before { content: "\e602";}

.contact > a[href̂="mailto"]:before { content: "\e601";}

elem[attr$="str"]Selects elements which have an attribute value ending with a

particular substring.

E.g. Styling links to different file types:

Download file: PDF Word

<section class="file-download"> <h4>Download file:</h4> <a href="http://domain.com/downloads/file.pdf">PDF</a> <a href="http://domain.com/downloads/file.doc">Word</a></section>

.file-download > a:before { font-family: 'icomoon'; /* other font declarations */ margin-right: 0.25em;}

.file-download > a[href$=".pdf"]:before { content: "\e603";}

.file-download > a[href$=".doc"]:before { content: "\e604";}

elem[attr*="str"]Selects elements which the substring somewhere in the attribute

value.

Great for modular code. E.g. Styling icon links with different typesof icons:

Follow us: Twitter YouTube

<section class="social"> <h4>Follow us:</h4> <a class="social-link" href="#"><i class="icon-font-twitter"></i>Twitter</a> <a class="social-link" href="#"><i class="icon-sprite-youtube"></i>YouTube</a></section>

i[class*="icon-"] { display: inline-block;}i[class*="icon-font-"]:before { font-family: 'icomoon'; /* other font declarations */}.icon-font-twitter:before { content: "\e606";}i[class*="icon-sprite-"] { background: url(lib/images/icon-sprite.png) no-repeat; /* other sprite declarations */}.icon-sprite-youtube { width: 24px; height: 28px; background-position: 0 0;}.social-link:hover > .icon-sprite-youtube { background-position: 0 -28px;}

LEVEL 3 & 4 SELECTOR HIGHLIGHTSStructural nth-child() / nth-of-type() 3

Logical :not(), :matches() 3/4

Relational :has() 4

:nth-child()Now in Level 3 we can choose any child of a containing element.

Heard ’round Springfield

Full demo and code

HTML:

<section class="character-list"> <article class="char simpsons"> <a href="#"> <img src="homer-simpson.jpg"><q>...</q> </a> </article> <article class="char flandereses"> <a href="#"> <img src="maude-flanders.jpg"><q>...</q> </a> </article> <article class="char bouviers"> <a href="#"> <img src="selma-bouvier.jpg"><q>...</q> </a> </article> ...</section>

Default positioning of quote bubble:

.char { position: relative;}.char q { position: absolute; top: -70%; left: -50%; /* other styles */}.char q:before, .char q:after { position: absolute; /* other styles */}.char q:before { right: 50%; bottom: -30px; /* other styles */}.char q:after { right: 52%; bottom: -50px; /* other styles */}

nth-child() positioning of quote bubble:

/* Left-most column */.char:nth-child(6n+1) q { left: -100%;}.char:nth-child(6n+1) q:after { right: 45%;}/* 2nd column in from left */.char:nth-child(6n+2) q { left: -85%;}.char:nth-child(6n+2) q:after { right: 40%;}/* Right-most column */.char:nth-child(6n+6) q { left: 20%;}.char:nth-child(6n+6) q:before { right: 50%;}.char:nth-child(6n+6) q:after { right: 60%;}

:nth-child()We get problems if we mix element types.

SIMPSONS

FLANDERESES

HTML:

<section class="character-list"> <h4 class="section-title">Simpsons</h4> <article class="char simpsons"> <a href="#"> <img src="homer-simpson.jpg"><q>...</q> </a> </article> ... <h4 class="section-title">Flandereses</h4> <article class="char flandereses"> <a href="#"> <img src="ned-flanders.jpg"><q>...</q> </a> </article> ...</section>

Fixed with :nth-of-type()SIMPSONS

FLANDERESES

Full demo and code

nth-of-type() positioning of quote bubble:

/* Left-most column */.char:nth-of-type(6n+1) q { left: -100%;}.char:nth-of-type(6n+1) q:after { right: 45%;}/* 2nd column in from left */.char:nth-of-type(6n+2) q { left: -85%;}.char:nth-of-type(6n+2) q:after { right: 40%;}/* Right-most column */.char:nth-of-type(6n+6) q { left: 20%;}.char:nth-of-type(6n+6) q:before { right: 50%;}.char:nth-of-type(6n+6) q:after { right: 60%;}

:not(s) & :not(s1[, s2]*)As of Level 3 we can exclude an element(s) from selections. When Level 4 is supported :not() will take a selector list.

<section class="character-list"> <article class="char simpsons"> <a href="#"> <img src="homer-simpson.jpg"><q>...</q> </a> </article> <article class="char flandereses"> <a href="#"> <img src="maude-flanders.jpg"><q>...</q> </a> </article> <article class="char bouviers"> <a href="#"> <img src="selma-bouvier.jpg"><q>...</q> </a> </article></section>

.char:not(.simpsons) img { opacity: 0.3;}.char:not(.simpsons) q { display: none;}

:matches(s1[, s2]*)When supported :matches() will allow us to include a selectoror group of selectors in the selection.

Previous slide uses the vendor prefixed selector to simulate what:matches() will do. :matches() is currently not supported in browsers I’vetested. Note: I would not recommend using the :any() selector as it’s on its wayout.

:any()

/* Using :matches() - STANDARD but no support yet */.char:matches(.simpsons, .flandereses) img { border-color: #0065BD;}

/* Using vendor prefixed :any() - NON-STANDARD */.char:-moz-any(.simpsons, .flandereses) img { border-color: #0065BD;}.char:-webkit-any(.simpsons, .flandereses) img { border-color: #0065BD;}

/* Using classes */.simpsons img, .flanders img { border-color: #0065BD;}

One useful application of :matches() would be for styling HTML5 headings.Since the document outline has been revised you can have multiple h1s on a page.Example CSS from MDN doing it the looong way:

/* Level 0 */h1 { font-size: 30px;}/* Level 1 */section h1, article h1, aside h1, nav h1 { font-size: 25px;}/* Level 2 */section section h1, section article h1, section aside h1, section nav h1,article section h1, article article h1, article aside h1, article nav h1,aside section h1, aside article h1, aside aside h1, aside nav h1,nav section h1, nav article h1, nav aside h1, nav nav h1, { font-size: 20px;}/* Level 3 *//* ... don't even think about it*/

When :matches() is supported:

/* Level 0 */h1 { font-size: 30px;}/* Level 1 */:matches(section, article, aside, nav) h1 { font-size: 25px;}/* Level 2 */:matches(section, article, aside, nav):matches(section, article, aside, nav) h1 { font-size: 20px;}/* Level 3 */:matches(section, article, aside, nav):matches(section, article, aside, nav):matches(section, article, aside, nav) h1 { font-size: 15px;}

:has(rs1[, rs2]*)Apparently new this year. When supported the :has() relational pseudo willallow us to select for elements which have a particular relationship to theelement(s) passed as parameters.

Examples from W3C spec:

Matches only a elements that contain an img child:

a:has(> img)

Matches a dt element immediately followed by another dt element:

dt:has(+ dt)

Matches section elements that don’t contain any heading elements:

section:not(:has(h1, h2, h3, h4, h5, h6))

NEED TO SUPPORT OLDER IE VERSIONS? is JS polyfill for Level 3 selectors.Selectivzr

SELECTOR PERFORMANCE

SOME CONSIDERATIONSBrowsers read selectors from right to left

Ideally want right-most “key” selector to be specific

IDs and classes are most efficient

Combinators (descendant, child, etc), attributes, pseudo-classes are not as efficient

I know what you are thinking...

OTHER CONSIDERATIONS. will be dead soon. Browsers are much

better than they used to be!

You should probably focus on other web performance bestpractices first (e.g. minimizing, using fonts/SVG or sprites,optimizing image file sizes, CDNs, caching, etc.)

There isn’t one solution–different websites require differentstrategies

Focus on maintainability...

IE6 is dead IE7 and 8

MAKING YOUR CSS MORE MAINTAINABLEDon’t tag qualify id or class selectors

Don’t “over-qualify” selectors

Minimize selector depth

Minimize general descendant/child selectors

Modularize code

Choose a naming/coding convention (SMACSS, BEM, etc.)

Decide what level of CSS efficiency is right for your site.

DON’T TAG QUALIFY ID OR CLASS SELECTORS/* Qualified */div#main-content {}ul.menu-list {}

/* Unqualified */#main-content {}.menu-list {}

ISSUESSelectors tied to particular mark up pattern

Increasing selector specificity

DON’T “OVER-QUALIFY” SELECTORS/* Over-qualified */.nav ul li a {}

/* Better */.nav a {}

ISSUESBrowsers will need to look up document tree anyways. Addingul and li not necessary

Increasing selector specificity

MINIMIZE SELECTOR DEPTH/* Not great */.content section ul li a {}

/* Better choices - Add class "list" to ul */.list > li > a {} .list a {}

The key is we reduced the number of levels the browser has towalk up.

Alternatives? Put class on li or individual a elements. Betterefficiency but at cost of maintenance?

MINIMIZE GENERAL DESCENDANT/CHILDSELECTORS

Especially involving universal selector. E.g.:

#main-content section {}ul li {}.nav > * {}

Alternatives? Can you use classes? Better mark up?

MODULARIZE CODEKeeps selector depth low

Great for portability with minimal CSS revisions

CSS preprocessors make modularizing easy. Create differentpartial file for each module.

<article class="news-item"> <h2 class="news-item-title">Title of Article</h2> <a href="#"><img class="news-item-thumb" src="" alt=""></a> <p class="news-item-excerpt">Excerpt</p></article>

.news-item {} /* module base class */

.news-item-title {}

.news-item-thumb {}

.news-item-excerpt {}

THANK YOU FOR LISTENING! QUESTIONS?Additional Resources