Possible Workarounds
As we’ve covered, there is no such thing as a parent selector, so selecting a parent isn’t possible. We might be tempted to sidestep the problem, by completely reconsidering the design so that selecting the parent is avoided. But if that isn’t possible then here are some potential approaches.
Using CSS :has()
Selector
The
:has selector is officially referred to as the relational pseudo-class. It matches elements based on their descendants, which are defined between the parentheses.
In the following example, it applies a
background-color to any
div containing an image caption. This seemingly addresses case 1.
- .page-content div:has( .img-caption ) {
- padding: 15px;
- background-color: #ccc;
- }
Or, if we want to be more specific, we can rewrite it to match any
div tag with the
.img-caption as the direct descendant.
- .page-content div:has( > .img-caption ) {
- padding: 15px;
- background-color: #ccc;
- }
This selector is drafted for
CSS Selector Level 4 though no browsers implement it yet. We will have to wait a little longer before this selector comes to light.
Using the jQuery Parent Selector
No single
CSS solution can fix our issues here, so let’s see what
JavaScript can do for us instead. In this example we are going to use jQuery for its robust APIs, convenience, and browser compatibility. At the time of writing, jQuery provides three methods to select parent elements.
parent(); this method selects the immediate parent of the targeted element. We can leverage this method to address all our use cases mentioned earlier in the tutorial.
 |
Image structure in legacy content. |
For example, we may use
parent() to add a special class to the wrapping element of the images within the content.
- $( ".img-caption" )
- .parent()
- .addClass( "has-img-caption" );
The above code will select the immediate element wrapping the image, regardless of the element type, adding the
has-img-caption class to give us more control over the element selection and styles, as follows.
 |
Image structure in legacy content with an extra class. |
parents() notice the plural form of this method. This method allows us to select the parent elements from the immediate, up to the root of the document, unless a selector is specified as the argument.
- $( ".img-caption" )
- .parents()
- .addClass( "has-img-caption" );
Given the above example, the
parents() method selects all the way from the
div tag which immediately wraps the image, the next
div, and lastly the
html, adding the
has-img-caption class to all elements.
 |
The has-img-caption class applied with the parents() method. |
Such overkill is redundant. The only element that will likely need to have the class added, in this case, is the immediate
div element. Hence we pass it in the method argument.
- $( ".img-caption" )
- .parents( "div" )
- .addClass( "has-img-caption" );
Here, the
parents() method will travel through the ancestor tree of the image, selecting any
div found and giving it the
has-image-caption class.
If that’s still overbearing, you can narrow the selection down to a single element by specifying the index. In the following example, we apply the class only to the first
div.
- var $parents = $( ".caption" ).parents( "div" );
- $parents[0].addClass( "has-img-caption" ); // select the first div add add the class.
parentsUntil(); this method selects the parent elements up to but not including the element specified in the parentheses.
- $( ".caption" )
- .parentsUntil( ".page-content" )
- .addClass( "has-img-caption" );
Given the above code, it will apply the
has-img-caption class to all the parent elements except the element with
.page-content.
In some cases, where you have gazillion nested elements, using the
parentsUntil() method is preferable. It is comparably faster than the
parents() method as it avoids using the jQuery selector engine (Sizzle) to travel across the entire DOM tree up to the document root.
Wrapping Up
Are we likely to have a
CSS Parent Selector at some point in the future?
Probably not. The kind of parent selector that we’ve discussed above has been proposed numerous times, but it has never passed the W3C draft stage for several reasons. Those reasons largely focus on browser performance, owing to the way browsers evaluate and render pages. The closest thing we’ll have in the future is the relational selector,
:has().
However, since the
:has() is not yet applicable,
JavaScript and jQuery are currently the most reliable approach. Bear in mind that DOM Traversal is a costly operation which may badly affect your site’s rendering performance. Avoid using
parents() or
parentsUntil() with other heavy operations like
animate(),
fadeIn() or
fadeOut().
Better yet, examine the
HTML structure whenever possible to see if selecting the parent element can be avoided completely!
Written by Thoriq Firdaus
If you found this post interesting, follow and support us.
Suggest for you:
CSS: Foundation classes on CSS
Coding Made Easy: HTML & CSS For Beginners
Bootstrap 4 Rapid web development framework HTML CSS JS