{"id":266050,"date":"2018-02-06T07:21:32","date_gmt":"2018-02-06T14:21:32","guid":{"rendered":"http:\/\/css-tricks.com\/?p=266050"},"modified":"2018-02-09T08:18:02","modified_gmt":"2018-02-09T15:18:02","slug":"counting-css-counters-css-grid","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/counting-css-counters-css-grid\/","title":{"rendered":"Counting With CSS Counters and CSS Grid"},"content":{"rendered":"
You\u2019ve heard of CSS Grid<\/a>, I\u2019m sure of that. It would be hard to miss it considering that the whole front-end developer universe has been raving about it for the past year.<\/p>\n Whether you\u2019re new to Grid or have already spent some time with it, we should start this post with a short definition directly from the words of W3C<\/a>:<\/p>\n Grid Layout is a new layout model for CSS that has powerful abilities to control the sizing and positioning of boxes and their contents. Unlike Flexible Box Layout, which is single-axis\u2013oriented, Grid Layout is optimized for 2-dimensional layouts: those in which alignment of content is desired in both dimensions.<\/p><\/blockquote>\n <\/p>\n In my own words, CSS Grid is a mesh of invisible horizontal and vertical lines.<\/strong> We arrange elements in the spaces between those lines to create a desired layout. An easier, stable, and standardized way to structure contents in a web page. <\/p>\n Besides the graph paper foundation, CSS Grid also provides the advantage of a layout model that\u2019s source order independent<\/strong>: irrespective of where a grid item is placed in the source code, it can be positioned anywhere<\/em> in the grid across both<\/em> the axes on screen. This is very<\/em> important, not only for when you\u2019d find it troublesome to update HTML while rearranging elements on page but also at times when you\u2019d find certain source placements being restrictive to layouts.<\/p>\n Although we can always move an element to the desired coordinate on screen using other techniques like In this post, we\u2019re going to demonstrate how we can use the source order independence of CSS Grid to solve a layout issue that\u2019s the result of a source order constraint. Specifically, we’re going to look at checkboxes and CSS Counters<\/a>.<\/p>\n If you\u2019ve never used CSS Counters, don\u2019t worry, the concept is pretty simple! We set a counter to count a set of elements at the same DOM level. That counter is incremented in the CSS rules of those individual elements, essentially counting them.<\/p>\n Here\u2019s the code to count checked and unchecked checkboxes:<\/p>\n In the above code, two counters are set at the root element using the Here’s a stripped-down version of what we get with this code:<\/p>\n See the Pen CSS Counter Grid<\/a> by CSS-Tricks (@css-tricks<\/a>) on CodePen<\/a>.<\/p>\n This is pretty cool. We can use it in to-do lists, email inbox interfaces, survey forms, or anywhere where users toggle boxes and will appreciate being shown how many items are checked and how many are unselected. All this with just CSS! Useful, isn\u2019t it?<\/p>\n But the effectiveness of Then, how else can we get the counters above<\/em> the checkboxes in our layout? This is where CSS Grid and its layout-rendering powers come into play.<\/p>\n We’re basically wrapping the previous HTML in a new And, here is the CSS for our grid:<\/p>\n This is what we get as a result (with some additional styling):<\/p>\n See the Pen CSS Counter Grid<\/a> by Preethi (@rpsthecoder<\/a>) on CodePen<\/a>.<\/p>\n See that? The counters are now located above the checkboxes!<\/p>\n We defined two columns on the grid element in the CSS, each accommodating its own content to their maximum size.<\/p>\n When we grid-ify an element, its contents (text including) block-ify, meaning they acquire a grid-level box (similar to block-level box) and are automatically placed in the available grid cells.<\/p>\n In the demo above, the counters take up both the grid cells in the first row as specified, and following that, every checkbox resides in the first column and the text after each checkbox stays in the last column.<\/p>\ntranslate<\/code>,
position<\/code>, or
margin<\/code>, they\u2019re both harder to code and to update for situations like building a responsive design, compared to true layout mechanisms like CSS Grid.<\/p>\n
Counting With Checkboxes<\/h3>\n
<input type=\"checkbox\">Checkbox #1<br>\r\n<input type=\"checkbox\">Checkbox #2\r\n<!-- more checkboxes, if we want them -->\r\n\r\n<div class=\"total\">\r\n <span class=\"totalChecked\"> Total Checked: <\/span><br>\r\n <span class=\"totalUnChecked\"> Total Unchecked: <\/span>\r\n<\/div><\/code><\/pre>\n
::root {\r\n counter-reset: checked-sum, unchecked-sum;\r\n}\r\n\r\ninput[type=\"checkbox\"] {\r\n counter-increment: unchecked-sum;\r\n}\r\n\r\ninput[type=\"checkbox\"]:checked {\r\n counter-increment: checked-sum;\r\n}\r\n\r\n.totalUnChecked::after {\r\n content: counter(unchecked-sum);\r\n}\r\n\r\n.totalChecked::after {\r\n content: counter(checked-sum);\r\n}<\/code><\/pre>\n
counter-reset<\/code><\/a> property and are incremented at their respective rules, one for checked and the other for unchecked checkboxes, using
counter-increment<\/code><\/a>. The values of the counters are then shown as contents of two empty
<span><\/code>s’ pseudo elements using
counter()<\/code>.<\/p>\n
counter()<\/code> wanes when we realize that an element displaying the total count can only appear after<\/em> all the elements to be counted in the source code. This is because the browser first needs the chance to count all the elements, before showing the total. Hence, we can\u2019t simply change the markup to place the counters above the checkboxes like this:<\/p>\n
<!-- This will not work! -->\r\n<div class=\"total\">\r\n <span class=\"totalChecked\"> Total Checked: <\/span><br>\r\n <span class=\"totalUnChecked\"> Total Unchecked: <\/span>\r\n<\/div>\r\n<input type=\"checkbox\">Checkbox #1<br>\r\n<input type=\"checkbox\">Checkbox #2<\/code><\/pre>\n
Adding Grid<\/h3>\n
<div><\/code> element that\u2019ll serve as the grid container:<\/p>\n
<div class=\"grid\">\r\n\r\n <input type=checkbox id=\"c-1\">\r\n <label for=\"c-1\">checkbox #1<\/label> \r\n <input type=checkbox id=\"c-2\">\r\n <label for=\"c-2\">checkbox #2<\/label> \r\n <input type=checkbox id=\"c-3\">\r\n <label for=\"c-3\">checkbox #3<\/label> \r\n <input type=checkbox id=\"c-4\">\r\n <label for=\"c-4\">checkbox #4<\/label> \r\n <input type=checkbox id=\"c-5\">\r\n <label for=\"c-5\">checkbox #5<\/label> \r\n <input type=checkbox id=\"c-6\">\r\n <label for=\"c-6\">checkbox #6<\/label>\r\n\r\n <div class=total>\r\n <span class=\"totalChecked\"> Total Checked: <\/span>\r\n <span class=\"totalUnChecked\"> Total Unchecked: <\/span>\r\n <\/div>\r\n\r\n<\/div><\/code><\/pre>\n
.grid { \r\n display: grid; \/* creates the grid *\/\r\n grid-template-columns: repeat(2, max-content); \/* creates two columns on the grid that are sized based on the content they contain *\/\r\n}\r\n\r\n.total { \r\n grid-row: 1; \/* places the counters on the first row *\/\r\n grid-column: 1 \/ 3; \/* ensures the counters span the full grid width, forcing other content below *\/\r\n}<\/code><\/pre>\n