{"id":5092,"date":"2014-12-22T20:56:50","date_gmt":"2014-12-23T03:56:50","guid":{"rendered":"http:\/\/g-liu.com\/blog\/?p=5092"},"modified":"2016-04-18T12:09:24","modified_gmt":"2016-04-18T19:09:24","slug":"css-last-child-vs-last-of-type-and-other-bizarre-conundrums","status":"publish","type":"post","link":"https:\/\/g-liu.com\/blog\/2014\/12\/css-last-child-vs-last-of-type-and-other-bizarre-conundrums\/","title":{"rendered":"CSS Gotchas: last-child vs. last-of-type and other bizarre conundrums"},"content":{"rendered":"<p>Suppose we have the following HTML:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&amp;amp;lt;div class=&amp;amp;quot;site-main&amp;amp;quot;&amp;amp;gt;\r\n    &amp;amp;lt;article&amp;amp;gt;First article&amp;amp;lt;\/article&amp;amp;gt;\r\n    &amp;amp;lt;article&amp;amp;gt;Second article&amp;amp;lt;\/article&amp;amp;gt;\r\n    &amp;amp;lt;article&amp;amp;gt;Third article&amp;amp;lt;\/article&amp;amp;gt;\r\n    &amp;amp;lt;article&amp;amp;gt;Fourth article&amp;amp;lt;\/article&amp;amp;gt;\r\n    \r\n    &amp;amp;lt;nav class=&amp;amp;quot;site-nav&amp;amp;quot;&amp;amp;gt;Previous ... Next&amp;amp;lt;\/nav&amp;amp;gt;\r\n&amp;amp;lt;\/div&amp;amp;gt;&amp;amp;lt;!-- .site-main --&amp;amp;gt;\r\n<\/pre>\n<p>We want to give the last <code>article<\/code> element a black border. So we write:<\/p>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\n.site-main article:last-child {\r\n    border: 5px solid black;\r\n}\r\n<\/pre>\n<p>But this does not work!<br \/>\n<!--more--><br \/>\nWhile our <em>intention<\/em> is to select the last article element, the <code>:last-child<\/code> pseudo-selector will not do so in this case. Why? There is an additional <code>nav<\/code> element below all the <code>article<\/code>, and this element truly is the <code>last-child<\/code> of <code>div.site-main<\/code>. In the case above, the expression <code>article:last-child<\/code> causes the browser&#8217;s rendering engine to grab the last child, which is a <code>nav<\/code>. Since this is not the correct element type, the browser <a href=\"https:\/\/css-tricks.com\/the-difference-between-nth-child-and-nth-of-type\/\" target=\"_BLANK\">does not apply the desired styles to it<\/a>.<\/p>\n<h1>Use last-of-type<\/h1>\n<p>If there was no <code>nav<\/code> element, then the last <code>article<\/code> would have been styled as intended. However, since we care to style the last child <em>that is an <code>article<\/code> element<\/em>, it is correct to use the <code>:last-of-type<\/code> selector. Now our CSS works:<\/p>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\n.site-main article:last-of-type {\r\n    border: 5px solid black;\r\n}\r\n<\/pre>\n<h1>Other X-of-type pseudo-selectors<\/h1>\n<p>In addition to <code>last-of-type<\/code>, there are also:<\/p>\n<ul>\n<li><code>first-of-type<\/code> &#8211; selects the first element of its parent with the matching type<\/li>\n<li><code>nth-of-type()<\/code> &#8211; selects the <em>n<\/em><sup>th<\/sup> child of its parent with the matching type<\/li>\n<\/ul>\n<p>These pseudo-selectors are extremely useful if you are trying to <a href=\"http:\/\/css-tricks.com\/the-difference-between-nth-child-and-nth-of-type\/\" target=\"_BLANK\">apply styles among a bunch of distinct elements<\/a>.<\/p>\n<h2>But wait! There&#8217;s another caveat<\/h2>\n<p>Consider the following:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&amp;amp;lt;div class=&amp;amp;quot;site-main&amp;amp;quot;&amp;amp;gt;\r\n    &amp;amp;lt;section class=&amp;amp;quot;banner&amp;amp;quot;&amp;amp;gt;First section&amp;amp;lt;\/section&amp;amp;gt;\r\n    &amp;amp;lt;section class=&amp;amp;quot;content&amp;amp;quot;&amp;amp;gt;Second section&amp;amp;lt;\/section&amp;amp;gt;\r\n    &amp;amp;lt;section class=&amp;amp;quot;content&amp;amp;quot;&amp;amp;gt;Third section&amp;amp;lt;\/section&amp;amp;gt;\r\n&amp;amp;lt;\/div&amp;amp;gt;\r\n<\/pre>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\nsection:first-of-type { \/* First section *\/ }\r\nsection.banner:first-of-type { \/* First section *\/ }\r\nsection.content:first-of-type { \/* No effect, why?? *\/ }\r\n<\/pre>\n<p>To understand why the last selector fails, we must understand what <strong>type<\/strong> means. The <strong>type<\/strong> in X-of-<strong>type<\/strong> refers only to the type of element (e.g. a <code>&lt;p&gt;<\/code> or <code>&lt;div&gt;<\/code>), and not its attributes such as ID or classes. In the example above: The reason why <code>section.content:first-of-type<\/code> didn&#8217;t do anything is because the first <code>section<\/code> element did not have class <code>content<\/code>. The second line worked, but is <span class=\"removed_link\" title=\"http:\/\/csswizardry.com\/2011\/09\/writing-efficient-css-selectors\/\">overqualified<\/span>, i.e. the <code>.banner<\/code> is completely redundant.<\/p>\n<p>In summary, when using <code>X-of-type<\/code> selectors, don&#8217;t attempt to introduce class, ID, or other attribute selectors into the mix. Doing so will only deceive you.<\/p>\n<h1>Putting it all together<\/h1>\n<p>The example below demonstrates the use of X-of-type selectors on a snippet of HTML code. A <a href=\"http:\/\/jsfiddle.net\/1g5j6g17\/\" target=\"_BLANK\">live demo is also available at JSFiddle<\/a>.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&amp;amp;lt;div class=&amp;amp;quot;site-main&amp;amp;quot;&amp;amp;gt;\r\n    &amp;amp;lt;article id=&amp;amp;quot;art-1&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;\/article&amp;amp;gt;&amp;amp;lt;!-- #1 --&amp;amp;gt;\r\n    &amp;amp;lt;aside class=&amp;amp;quot;tweet&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;\/aside&amp;amp;gt;&amp;amp;lt;!-- #2 --&amp;amp;gt;\r\n    &amp;amp;lt;article id=&amp;amp;quot;art-2&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;\/article&amp;amp;gt;\r\n    &amp;amp;lt;aside class=&amp;amp;quot;quote&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;\/aside&amp;amp;gt;&amp;amp;lt;!-- #5 --&amp;amp;gt;\r\n    &amp;amp;lt;section class=&amp;amp;quot;ads&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;\/section&amp;amp;gt;\r\n    &amp;amp;lt;aside class=&amp;amp;quot;quote&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;\/aside&amp;amp;gt;&amp;amp;lt;!-- #4, 5 --&amp;amp;gt;\r\n    &amp;amp;lt;article id=&amp;amp;quot;art-3&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;\/article&amp;amp;gt;\r\n    &amp;amp;lt;aside class=&amp;amp;quot;tweet&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;\/aside&amp;amp;gt;\r\n    &amp;amp;lt;aside class=&amp;amp;quot;quote&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;\/aside&amp;amp;gt;&amp;amp;lt;!-- #5 --&amp;amp;gt;\r\n    &amp;amp;lt;article&amp;amp;gt;3&amp;amp;lt;\/article&amp;amp;gt;&amp;amp;lt;!-- #3 --&amp;amp;gt;\r\n    \r\n    &amp;amp;lt;nav class=&amp;amp;quot;site-navigation&amp;amp;quot;&amp;amp;gt;1 2 3 4 Next...&amp;amp;lt;\/nav&amp;amp;gt;\r\n&amp;amp;lt;\/div&amp;amp;gt;\r\n<\/pre>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\naside:first-child { \/* affects nothing *\/ }\r\narticle:last-child { \/* affects nothing *\/ }\r\narticle:first-of-type { \/* 1 *\/ }\r\naside:first-of-type { \/* 2 *\/ }\r\naside.quote:first-of-type { \/* affects nothing *\/ }\r\narticle:last-of-type { \/* 3 *\/ }\r\naside:nth-child(3) { \/* affects nothing *\/ }\r\naside:nth-of-type(3) { \/* 4 *\/ }\r\naside.quote:nth-of-type(odd) { \/* 5 *\/ }\r\n<\/pre>\n<h1>Browser compatibility<\/h1>\n<p>All of these pseudo-selectors were introduced with CSS3. To see the browser support for these selectors, <a href=\"http:\/\/css-tricks.com\/almanac\/selectors\/l\/last-of-type\/\" target=\"_BLANK\">check out this page on Can I Use<\/code>.<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content --><!-- AddThis Related Posts generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>last-child may be popular, but in many cases, it&#8217;s last-of-type that gets the job done. Even then, there are some subtle surprises that may surface.<!-- AddThis Advanced Settings generic via filter on wp_trim_excerpt --><!-- AddThis Share Buttons generic via filter on wp_trim_excerpt --><!-- AddThis Related Posts generic via filter on wp_trim_excerpt --><\/p>\n","protected":false},"author":2,"featured_media":5103,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"footnotes":"","jetpack_publicize_message":"#CSS Gotchas: last-child vs. last-of-type and other bizarre conundrums","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[830],"tags":[],"jetpack_publicize_connections":[],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/g-liu.com\/blog\/wp-content\/uploads\/2014\/12\/css-selectors.jpg","jetpack_shortlink":"https:\/\/wp.me\/p2Zt3y-1k8","_links":{"self":[{"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/posts\/5092"}],"collection":[{"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/comments?post=5092"}],"version-history":[{"count":15,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/posts\/5092\/revisions"}],"predecessor-version":[{"id":5660,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/posts\/5092\/revisions\/5660"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/media\/5103"}],"wp:attachment":[{"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/media?parent=5092"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/categories?post=5092"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/tags?post=5092"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}