Menu Search
Jump to the content X X

Today, too many websites are still inaccessible. In our new book Inclusive Design Patterns, we explore how to craft flexible front-end design patterns and make future-proof and accessible interfaces without extra effort. Hardcover, 312 pages. Get the book now →

Quantity Ordering With CSS

Here is your mission, should you choose to accept it: create a table of items. Each item should span a third of the content area, with the fourth item starting on a new row, much like floats. However, a particular item must always display the price at the end of the first row.

So if there are only two elements, the price element would be second. But if there are more than three items, the price would be the last element in the first row.

You might assume that JavaScript would be the best solution — just loop over the items, and if there are more than three, update the styling. But what if I told you could do it with CSS alone?

Pure CSS Counting Link

I’ve gone all in on flexbox lately, teaching it right alongside floats as a layout method at our little project called HackerYou, and I have found that students take to it well. The flexbox specification contains properties that enable us to modify markup in new ways. One of these is order, which allows us to modify the presentational order of content without touching the markup or structure.

Used with media queries, order is extremely useful, enabling us to change the content’s order with the viewport size. That got me thinking: Why can’t we change the order of elements according to the amount of content?

Quantity Queries Link

An idea explored by Lea Verou1, André Luis2 and Heydon Pickering3, quantity queries count the number of sibling elements and apply styles if a certain number are present.

What if we combined quantity queries and the order property to change how content is read according to how much of it there is?

Using Flexbox Link

Flexbox, or the “Flexible Box Layout Module4,” is a CSS specification that allows for content to be laid out in any direction and for children to be sized to their parent easily. Originally introduced in 2009, flexbox has gone through many changes over the years. However, it is supported5 in all current browsers, with the exception of Internet Explorer 9+.

One of the most significant changes within flexbox is the naming syntax of associated properties and values. Because the specification evolved over years, browser vendors would use the syntax that was being developed at the time. So, using vendor prefixes is recommended to ensure support across legacy browsers.

One recommended tool for managing cross-browser support in CSS is Autoprefixer6, which is typically included in preprocessors and Gulp and Grunt files.

Understanding Order Link

Before we dig into quantity queries and how they work, we should understand how to use the order property. First, we need to wrap the content with a parent element and apply display: flex to it.

Here’s the HTML:

<div class="container">
  <p class="itemOne">Hello</p>
  <p class="itemTwo">World!</p>
</div>

And here’s the CSS:

.container {
  display: flex;
}

See the Pen LVVXxz7 by Drew Minns (@drewminns30211714118) on CodePen31221815129.

By default, elements will appear in their order in the markup. All child elements of a flexbox parent share an order value of 1.

This value is unitless and simply refers to the order of the element relative to the other elements around it. However, we can change the value of an individual element using the order property.

p.itemOne {
  order: 2;
}

See the Pen Really Good Work Article 10 by Drew Minns (@drewminns30211714118) on CodePen31221815129.

In the example above, we’ve changed the order of p.itemOne to a value of 2, making it fall after p.itemTwo and thereby changing the presentational order for the user. Note that the markup remains the same, however.

Counting With CSS Link

Media queries, eh? Such an awesome tool for applying CSS when certain conditions are met. Those conditions could be device type, size, color and more — pretty powerful stuff. But the query applies only to the device that the viewer is using; there is no defined CSS method for querying the amount of content in an element.

If we get creative with existing CSS pseudo-selectors, however, we can build tools that count the number of children in an element and then apply styles accordingly. For this example, let’s use a simple ordered list:

<ul class="ellist">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li class="target">6</li>
</ul>

The magic of counting sibling elements is in the selector below. This example applies styles to elements when four or more are available.

ul.ellist li:nth-last-child(n+4) ~ li,
ul.ellist li:nth-last-child(n+4):first-child {
  // styles go here
}

See the Pen WvvYyN13 by Drew Minns (@drewminns30211714118) on CodePen31221815129.

Wait, No. That’s Insane! Link

Yep, that’s the selector. In English, it could be translated as this: “When there are four or more child elements, get the other list items and the first child.”

Let’s break this down. First, the counting:

ul.ellist li:nth-last-child(n+4) {
  // Styles!
}

This translates as, “Go to the last child and count back four children.” Apply the styles to the fourth element and all elements before it.

Go ahead and experiment by editing the Codepen and changing the selector to a different number.

See the Pen Pqqvqp16 by Drew Minns (@drewminns30211714118) on CodePen31221815129.

So, there it is, counting. If fewer than four siblings are counted, nothing is selected and no styles are applied. We can now modify this selector to select all li elements using the general sibling combinator19.

ul.ellist li:nth-last-child(n+4) ~ li {
  // Styles!
}

The problem is that this doesn’t select the first child element. We can append another selector to do that:

ul.ellist li:nth-last-child(n+4) ~ li,
ul.ellist li:nth-last-child(n+4):first-child {
  // Styles!
}

Of course, we can make the selector more agnostic simply by supplying the parent element and letting it choose all of the children. We do this with the * selector.

element > *:nth-last-child(n+4) ~ *,
element *:nth-last-child(n+4):first-child {
  // Styles!
}

Ordering Based On Quantity Link

Now that we have explored how to count with CSS selectors and how to use flexbox to order content, let’s mix them together to build a tool that orders elements based on the number of siblings.

Again, we’re trying to make our last element be the third element (i.e. appear as the last element in the first row) when there are more than three siblings.

Let’s apply some CSS for some presentational styling. We’ll apply display: flex to the parent container, which allows us to apply the order property on the child elements. As well, we’ll apply some default styling to the .target element to differentiate it.

ul.ellist {
  margin: 20px 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-flow: row wrap;
}
ul.ellist > * {
  border: 10px solid #27ae60;
  text-align: center;
  flex: 1 0 calc(33.33% - 20px);
  padding: 20px;
  margin: 10px;
}
.target {
  color: white;
  background: #2980b9;
  border: 10px solid #3498db;
}
ul.ellist, ul.ellist > * {
  box-sizing: border-box;
}
ul.ellist {
  margin: 20px 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-flow: row wrap;
}
ul.ellist > * {
  border: 10px solid #27ae60;
  text-align: center;
  flex: 1 0 calc(33.33% - 20px);
  padding: 20px;
  margin: 10px;
}
ul.ellist .target {
  color: white;
  background: #2980b9;
  border: 10px solid #3498db;
}

Now that we have a base style to work with, we can create some logic to order our items accordingly. Again, by default, all elements have an order value of 1 and are displayed according to the order in which they appear in the markup.

Using a quantity query, we can count whether there are more than three items.

ul.ellist > *:nth-last-child(n+3) {
  // Styles!
}

We can then modify our query to select the .target element only if the number of items is met. For now, we’ll apply an order of -1, so that it appears at the beginning of our list.

ul.ellist > *:nth-last-child(n+3) ~ .target {
  order: -1;
}

Voilà! We’ve just styled an element based on the numbers of siblings it has. Using this code, we can put one element in front of another.

But what if it needs to go between items?

Some Logical Thinking Link

Here is the problem, in three arguments:

  • By default, all items have an order set to 1. We need the items at the beginning of the list to keep that order value.
  • Our target will be presented at the end of the first row. So, we need the target’s order value to be higher than the ones in the beginning — i.e. 2.
  • We need all items from three onward to have a higher order than our target and lead elements. So, they will have an order value of 3.

How about this?

Because all items have a default value of 1, we don’t need to declare that. Let’s allow our target element to have an order value of 2 via our quantity query, effectively placing it higher than the others.

ul.ellist > *:nth-last-child(n+3) ~ .target {
  order: 2;
}

Then, using another quantity query that utilizes nth-child(), we will count from the beginning of the list, rather than from the end. Because our .target quantity query is more specific, the last element will be ignored, but all others three and higher will have their order changed.

ul.ellist > *:nth-last-child(n+3) ~ .target {
  order: 2;
}
ul.ellist > *:nth-child(n+3) {
  order: 3;
}

Whoa! Let’s Go Over That Again Link

We counted from the end of a parent element if there were a number of child elements. If there were, we applied some styles to an element of our choice. We then counted from the beginning and applied styles to all elements past that point.

The beautiful part is that if we were to remove elements, the target element would still appear in the correct position.

<ul class="ellist">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li class="target">4</li>
</ul>

The Resulting Task Link

My first thought when given this task was to use a programming language. Because the website was built on WordPress, I could modify “the loop” to count and inject the element where needed.

However, because I’m building the website for a front-end development school, I wanted to do it with pure CSS and explore the possibilities that flexbox’s order allows.

Below is an example of the resulting page, done entirely with CSS.

See the Pen Quantity Ordering20 by Drew Minns (@drewminns30211714118) on CodePen31221815129.

Using It In The Real World Link

Sass Link

Quantity queries are a fairly new concept, and writing the selectors can be a bit of a challenge. Nevertheless, the community is embracing the concept and is building tools and writing Sass mixins that can help us write queries effectively. Libraries such as the one by Daniel Guillan23, called a Quantity Queries Mixin24, enable us to write media queries as simple includes.

@include at-least($count) { … }
@include between($first, $last) { … }

A plethora of articles also explain the concept and power behind this. James Steinbach25 wrote a great article on “Using Sass for Quantity Queries26.”

PostCSS Link

PostCSS is a new tool that allows CSS to be transformed with JavaScript. The current PostCSS ecosystem includes many community-developed plugins, including a Quantity Query27 plugin.

The plugin allows for custom pseudo-selectors to target values within a certain range, at least, or at most.

p:at-least(4) { … }

p:between(4,6) { … }

Browser Support Link

Currently, support for both CSS pseudo-selectors and flexbox28 is great in modern browsers. If your project targets users on IE 10 and above, you can use quantity queries and flexbox ordering together.

Where to Use It Link

When building websites, we often use programming languages that allow us to count and modify our content as needed. However, as CSS has improved, we’ve moved away from programming languages into advanced CSS properties.

One example is CSS animations. What was previously possible only through Flash or JavaScript is now achievable with pure CSS, a language for defining the presentation of our content.

Quantity ordering enables us to remove modified loops that count and insert content accordingly, allowing our content to be read semantically.

A great example of the usefulness of quantity ordering would be a news website with advertising. In the markup, all articles are organized together, and the ads are placed at the end. In terms of accessibility, this allows for an uninterrupted flow of content. The ads can then be placed throughout the content, using quantity ordering only on a presentational layer.

See the Pen vOLGPg29 by Drew Minns (@drewminns30211714118) on CodePen31221815129.

While ordering can be used to change the presentational display of elements, for accessibility, it can damage the experience. Be aware of how content flows and how it will be read on accessibility devices.

Conclusion Link

Quantity queries and quantity ordering are advanced concepts and might be scary for beginners. However, as we move presentational styling away from programming languages and into CSS, we should use these tools more and more.

Even as many members of our industry explore content queries32, we can now use quantity queries to modify the order of content simply by counting.

Excerpt image: Markus Spiske33

(ds, ml, al)

Footnotes Link

  1. 1 http://lea.verou.me/2011/01/styling-children-based-on-their-number-with-css3/
  2. 2 http://andr3.net/blog/post/142
  3. 3 http://alistapart.com/article/quantity-queries-for-css
  4. 4 http://www.w3.org/TR/2015/WD-css-flexbox-1-20150514/
  5. 5 http://caniuse.com/#search=flex
  6. 6 https://github.com/postcss/autoprefixer
  7. 7 'http://codepen.io/drewminns/pen/LVVXxz/'
  8. 8 'http://codepen.io/drewminns'
  9. 9 'http://codepen.io'
  10. 10 'http://codepen.io/drewminns/pen/oXXQBo/'
  11. 11 'http://codepen.io/drewminns'
  12. 12 'http://codepen.io'
  13. 13 'http://codepen.io/drewminns/pen/WvvYyN/'
  14. 14 'http://codepen.io/drewminns'
  15. 15 'http://codepen.io'
  16. 16 'http://codepen.io/drewminns/pen/Pqqvqp/'
  17. 17 'http://codepen.io/drewminns'
  18. 18 'http://codepen.io'
  19. 19 http://www.w3.org/TR/selectors/#general-sibling-combinators
  20. 20 'http://codepen.io/drewminns/pen/waarLQ/'
  21. 21 'http://codepen.io/drewminns'
  22. 22 'http://codepen.io'
  23. 23 http://www.danielguillan.com/
  24. 24 https://github.com/danielguillan/quantity-queries
  25. 25 http://jamessteinbach.com/
  26. 26 http://www.sitepoint.com/using-sass-quantity-queries/
  27. 27 https://github.com/pascalduez/postcss-quantity-queries
  28. 28 http://caniuse.com/#search=flexbox
  29. 29 'http://codepen.io/drewminns/pen/vOLGPg/'
  30. 30 'http://codepen.io/drewminns'
  31. 31 'http://codepen.io'
  32. 32 https://github.com/marcj/css-element-queries
  33. 33 https://www.flickr.com/photos/markusspiske/18544440564/in/album-72157644611527928/

↑ Back to top Tweet itShare on Facebook

Advertisement

Drew Minns is a Developer, Designer and Educator from Toronto, Canada. Currently working as Lead Instructor and Developer for HackerYou, Drew stays on the edge of the industry to educate those around him.

  1. 1

    Nice, if you have the luxury of no <ie10 visitors.

    11
  2. 2

    Tommy Rolchau Mathiesen

    July 14, 2015 7:27 pm

    Pretty sweet!

    Though, the same effect can be achieved using the :not selector:

    section.articles > article:nth-child(n+4):not(.ad) {
    order: 3;
    }

    ;)

    6
    • 3

      Oh wow, that’s great!! I did not think of using the :not() selector so thank you!

      2
  3. 4

    Great, thanks!
    Btw, does anybody know if the flexbox order-property is animatable?

    1
    • 5

      It is not animatable (at least based on my usage of flexbox over the last two years). If you think about it, it kind of makes sense why it wouldn’t be. Changing the order isn’t just about the current element, but the other elements that have orderable properties, too.

      It stinks, though. I wish it were animatable; lots of cool opportunities if that were the case.

      One solution would be to create an animation keyframe that set the element to position fixed, moved the element to the position of order:1, and then you removed the animation, and set an inline style or a class that changed the order state to the current one.

      2
  4. 6

    Yoha, fantastic but I think this is mostly a useless approach these years. If one would really use some of those features (mix programming with styling), he or she has to adapt any of them with js to stay compatible. We still have a lot of ie<11, ff<29, opera <12, safari<6, chrom/ium<29 mobile or not browser in the wild wich we have to support. IT's tedious to adapt flex layouts to all those devices with all those different browsers, with all those different abilities. But it's completely obnoxious to widen the required effort with such an approach if this could be avoided by using simple javascript.

    4
  5. 7

    Mohammad Hamza

    July 15, 2015 1:02 am

    IE10 and above, that is not a good browser support. But this one is quite helpful to kick Javascript and use CSS only. Thanks anyways.

    -1
  6. 8

    Elliott Greaves

    July 15, 2015 1:58 am

    Flex is a great CSS feature, my only concern is actually using it in live projects; at this point in time (a question not a statement) are we using this nifty feature and creating more work for ourselves in regards to backwards compatibility?

    2
    • 9

      Yes, I think we are. So many articles always focus on the art of the possible, that they forget to give the 100+ lines of extra code for supporting IE9+ and other older but still statistically significant browsers. Doing things purely with CSS is amazing, and I do it as much as I can – so long as the experience of “style” (which is what CSS is) is not destroyed by trying to creating critical meaning through style alone. Using only CSS3+ rules to create meaning is antithetical to CSS and the modern web. Get your HTML right, understand the limitations of your audience and then code CSS to suit. Finally, introduce JS to plug the gaps.

      We all work in front-end devlopmemt – it is not Utopia nor perfect, so we have to be pragmatic. For example, I would love to start using flex box, but the tiny gains versus the extra code for browsers that don’t support it means that for today, I will stick with my rows and columns CSS, and keep monitoring support until i can make a production switch.

      4
      • 10

        Your decision to support older browsers should be made on a case by case basis.

        Flexbox actually has pretty good support, all browsers latest versions support it. It’s only if you’re going back to IE9 and IE8 that you’ll encounter issues – or much older versions of Safari/Chrome etc.

        Even then, most flexbox layouts can be recreated largely using floats, so it shouldn’t be a big deal to build in a fallback for IE8/9.

        2
  7. 11

    Tommy Rolchau Mathiesen

    July 15, 2015 10:20 pm

    Its great to see so many people defending the lowest common denominator – the old browsers. Developers trying to make old browsers act like modern ones, or degrade modern browsers to be old, are exactly whats keeping them alive – AWSOME!

    -6
    • 12

      That’s not really true though. Many things keep older browsers alive:

      Corporate IT that has to run older browsers to use legacy Enterprise software

      OS lock-in on mobile devices from phone companies who modify the OS and make it hard/impossible to update the stock browser without sufficient knowledge (upgrading Android from a modified version to a clean release is hard for many people)

      Income and older equipment. There are home users still run XP, because it works, and just use IE8 because it’s what they know.

      That’s just three examples of why older browsers are still out there and need to have a level of support.

      9
  8. 13

    He said what if I said you ‘could’ not, you ‘must’.

    0
  9. 14

    طراحی سایت

    July 16, 2015 3:41 pm

    Great Content
    I have referred to it in your site

    1
  10. 15

    In between all these discussions about pros/cons of supporting older browsers, it’s kind of funny to notice that the last codepen example doesn’t work as expected (no ad is shown) in Firefox 39.0 =) All the other browsers are fine, though.

    0
    • 16

      Check your ad blocker – I ran into the same issue and fixed it by disabling it on Smashing (their ads are static and therefore don’t bother me.

      1
  11. 17

    Louis Lazaris

    July 18, 2015 5:10 am

    Drew, really interesting technique. I’m going to have to examine this a little more closely when I’m off mobile. :)

    Two things:

    Near the beginning, you said flexbox is “supported in all current browsers, with the exception of Internet Explorer 9+.” I think you mean “with the exception of IE9 and below”. The “+” sign indicates all IE versions from 9 and up.

    Also, IIRC, you are a good friend of Josh K, who I used to work with. You guys still in touch? Tell him I said hi! :)

    2
  12. 18

    Nice trick. Thanks :)

    -1
  13. 19

    David Mcclemans

    July 24, 2015 7:02 am

    Excellent examples!
    Simple design is winning. Two things are very clear on eCommerce website:
    1) Business that company is doing
    2) Call for action (in the form of buttons).

    Unfortunately, many eCommerce site companies don’t understand that message hierarchy is crucial for their website success. So instead of communicating one, the most important massage, they want to communicate more, also the most important messages, and that is when design gets messy and useless. So many eCommerce site is developed by Discover Web Design Brisbane. Lots of coffiendance they give to high success those eCommerce site…

    Make it clean, make it simple.

    1
  14. 20

    Interesting point of view – I agree that many designers, these days, get a little carried away with design and don’t focus on simplicity in addition to designing for user experience. I’ve sort of always tried to keep things as minimal as possible.
    The D Website Design Team

    1
  15. 21

    css is impotant for web-designing. you can make attractive web-site using css. this blog have great information.

    0
  16. 22

    Online Forums

    July 30, 2015 11:58 am

    Good post

    0
  17. 23

    Yes Finally we can handle counting and ordering with pure CSS. Amazing..

    0
  18. 24

    Great article!

    Counting with the :nth-last-child selector is very useful for me. I don’t use flexbox (yet), only floats or inline-block elements, thereby support is IE9+.

    With the selectors I created justified and centered grids who depend on the amount of items. If they have 3 items, their width is 33%, 2 items -> 50% etc. Also the last row of items can be given specfic styles. In the centered grid if there are 7 items I give them width: 26%, then the 4rd item is moved to the next row, so you get a nice piramide shape :)

    The difference between :nth-last-child and :nth-last-of-type can be used if you need to exclude one item in the list. A span with buttons for example, or an add ;)

    1

↑ Back to top