{"id":5514,"date":"2010-04-14T04:33:18","date_gmt":"2010-04-14T11:33:18","guid":{"rendered":"http:\/\/css-tricks.com\/?p=5514"},"modified":"2021-04-09T06:52:28","modified_gmt":"2021-04-09T13:52:28","slug":"child-and-sibling-selectors","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/child-and-sibling-selectors\/","title":{"rendered":"Child and Sibling\u00a0Selectors"},"content":{"rendered":"\n

Do you know what the difference between these selectors are?<\/p>\n\n\n\n

ul li { margin: 0 0 5px 0; }\nul > li { margin: 0 0 5px 0; }<\/code><\/pre>\n\n\n\n

I’ll admit it took me longer than it probably should have (way back when) when I was learning the basics of CSS. In both cases, they are selecting list items that are children of unordered lists. But there is a difference between children<\/a> and descendants<\/a>.<\/p>\n\n\n\n\n\n\n\n

The first selector above is a decendant selector<\/em>. It will select any list items that are anywhere underneath an unordered list in the markup structure. The list item could be buried three levels deep within other nested lists, and this selector will still match it. The second selector above is a child combinator selector<\/em>. This means it will only select list items that are direct children of an unordered list. In otherwords, it only looks one level<\/em> down the markup structure, no deeper. So if there was another unordered list nested deeper, the list item children of it will not be targeted by this selector.<\/p>\n\n\n\n

I think everyone understands the basic decendent selector, but let’s do a quick overview of the other selectors in this style: the child combinator<\/strong>, the adjacent sibling combinator<\/strong>, and the general sibling combinator<\/strong>.<\/p>\n\n\n

Child combinator<\/h4>\n\n\n

This one we covered in the intro to this article. Let’s drive that same example home with a visual:<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n\n

I think the nested list is a perfect example of why this selector is useful. It can be thought of as a way to prevent styling from cascading down further than you would like it to. Maybe you want to make the outer-most list items large and header-like, but the nested lists smaller and more body-copy like. Using a child combinator you can select only those top level list items and not worry about the large\/header styling cascading down to the nested lists and having to fight against that styling.<\/p>\n\n\n

Adjacent sibling combinator<\/h4>\n\n\n

An adjacent sibling<\/a> combinator selector allows you to select an element that is directly after another specific element.<\/p>\n\n\n\n

p + p { font-size: smaller; } \/* Selects all paragraphs that follow another paragraph *\/\n#title + ul { margin-top: 0; } \/* Selects an unordered list that directly follows the element with ID title *\/<\/code><\/pre>\n\n\n\n

These selectors can help you apply styling in a contextual way. Perhaps you have a bunch of articles on a site. Most of them start with <p> elements and it looks great. But some of them start with a <ul>, which have top and bottom margin on your site to look good within an article. But when they start an article it causes an awkward gap. The latter selector above would zero out that top margin when it begins an article (immediately succeeds a title).<\/p>\n\n\n\n

Hopefully helpful graphic:<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n

General sibling combinator<\/h4>\n\n\n

The general sibling combinator selector is very similar to the adjacent sibling combinator selector we just looked at. The difference is that that the element being selected doesn’t need to immediately succeed<\/em> the first element, but can appear anywhere after it.<\/p>\n\n\n\n

If we use the same example structure as above, the last <p> element will be selected by p ~ p<\/tt> as well, because it is preceded by another <p> element, even though not directly<\/em>.<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n\n

Note that in both the general sibling and adjacent sibling selectors the logic takes place within the same parent element. That’s what siblings means… sharing the same parent. In the graphical examples above, that’s what the wrapping <div> is there for. If there was another <p> element after that <div>, it would still be selected by both div ~ p<\/tt> and div + p<\/tt> though, as it would be a sibling and an adjacent sibling to that <div>.<\/p>\n\n\n

Browser Support<\/h3>\n\n\n

These are all good-to-go in IE 8 and up and all other modern browsers. IE 7 also has support, but be aware that HTML comments can screw them up and cause them to not match when in between siblings.<\/p>\n\n\n\n

If you need deeper support than that, the ie7-js project<\/a> (now updated all the way to ie9.js) will get you support for all of this back to even IE 5.5 with a single simple JavaScript file inclusion.<\/p>\n\n\n

Wish upon a star<\/h3>\n\n\n

I’ve said it many times before, but one of the major missing selector styles in CSS is some kind of “contains” (or “has” or “qualified” or whatever you want to call it. The idea being like “select all paragraphs that contain images”.<\/p>\n\n\n\n

It could be<\/a> like this:<\/p>\n\n\n\n

p < img { width: 150%; } \/* Not real! *\/<\/code><\/pre>\n\n\n\n

Apparently the powers that be have rejected it a number of times for some complicated reasons (speed related, I think). jQuery can do it:<\/p>\n\n\n\n

$(\"p:has(img)\")<\/code><\/pre>\n\n\n\n

And can even be adjusted<\/a> to use the “<” syntax:<\/p>\n\n\n\n

jQuery.parse.push(\/^\\s*(<)(\\s*)(.*)$\/);\njQuery.expr[\"<\"] = jQuery.expr[\":\"].has;<\/code><\/pre>\n\n\n

The Spec<\/h3>\n\n\n

Doesn’t hurt to read over the spec<\/a> for this stuff either.<\/p>\n","protected":false},"excerpt":{"rendered":"

Do you know what the difference between these selectors are? I’ll admit it took me longer than it probably should have (way back when) when I was learning the basics of CSS. In both cases, they are selecting list items that are children of unordered lists. But there is a difference between children and descendants.<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4,20],"tags":[478],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":150992,"url":"https:\/\/css-tricks.com\/targetting-menu-elements-submenus-navigation-bar\/","url_meta":{"origin":5514,"position":0},"title":"Targeting Menu Elements with Submenus in a Navigation Bar","date":"September 23, 2013","format":false,"excerpt":"The following is a guest post by Ray Messina. Ray was interested in sharing this technique as a way to pay forward things he's learned from this site in the past, which is awesome. You might be aware of the jQuery .has method, which allows you to select an element\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":354115,"url":"https:\/\/css-tricks.com\/supports-selector\/","url_meta":{"origin":5514,"position":1},"title":"@supports selector()","date":"October 19, 2021","format":false,"excerpt":"I didn't realize the support for @supports determining selector support was so good! I usually think of @supports as a way to test for property: value pair support. But with the selector() function, we can test for selector support as well. It looks like this: @supports selector(:nth-child(1 of .foo)) {\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/02\/supports-code.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":376342,"url":"https:\/\/css-tricks.com\/has-is-an-unforgiving-selector\/","url_meta":{"origin":5514,"position":2},"title":":has is an unforgiving selector","date":"January 11, 2023","format":false,"excerpt":"A little thing happened on the way to publishing the CSS :has() selector to the ol' Almanac. I had originally described :has() as a \"forgiving\" selector, the idea being that anything in its argument is evaluated, even if one or more of the items is invalid. \/* Example: Do not\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/06\/where-specificity.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":336424,"url":"https:\/\/css-tricks.com\/the-css-has-selector\/","url_meta":{"origin":5514,"position":3},"title":"The CSS :has Selector (and 4+ Examples)","date":"March 17, 2021","format":false,"excerpt":"The CSS :has selector helps you select elements when they contain other elements that match the selector you pass into :has().","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/has-pseudo-example.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":343613,"url":"https:\/\/css-tricks.com\/using-the-specificity-of-where-as-a-css-reset\/","url_meta":{"origin":5514,"position":4},"title":"Using the Specificity of :where() as a CSS Reset","date":"July 12, 2021","format":false,"excerpt":"I don\u2019t know about you, but I write these three declarations many times in my CSS: ul { padding: 0; margin: 0; list-style-type: none; } You might yell at me and say I can just put those in my CSS resets. I wish I could, but I don\u2018t want to\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/06\/where-specificity.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":176856,"url":"https:\/\/css-tricks.com\/how-css-selectors-work\/","url_meta":{"origin":5514,"position":5},"title":"Beginner Concepts: How CSS Selectors Work","date":"August 9, 2014","format":false,"excerpt":"Are you new to CSS? This article is for you! Perhaps the biggest key to understanding CSS is understanding selectors. Selectors are what allows you to target specific HTML elements and apply style to them. Let's not think about style right now though, let's just focus on the selecting. In\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2014\/08\/HTMLCSS.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]}],"featured_media_src_url":null,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/5514"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=5514"}],"version-history":[{"count":9,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/5514\/revisions"}],"predecessor-version":[{"id":338033,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/5514\/revisions\/338033"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=5514"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=5514"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=5514"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}