Css get all parents

Selecting Parent Elements With CSS and jQuery

Thoriq Firdaus

Thoriq Firdaus Last updated May 2, 2016

There have been occasions where I’ve wished I was able to select a parent element with CSS–and I’m not alone on this matter. However, there isn’t such thing as a Parent Selector in CSS, so it simply isn’t possible for the time being.

In this tutorial we will walk through a few cases where having a CSS parent selector might come in handy, along with some possible workarounds. Let’s get started!

Wait, What’s a Parent Selector?

CSS selectors allow us to target elements, moving down and across the DOM tree, getting more specific as we do so. Here’s an example of the kind of selector you might find in Bootstrap–it travels down the DOM tree from the nav.navbar-dark element, to the ul , the li , then finally the a.nav-link .

.navbar-dark .navbar-nav .nav-item .nav-link  

A parent selector would allow us to travel back up the DOM, targeting the parent elements of certain things. For example, we would be able to target the parent of .nav-link elements by using:

Note: this example is pure pseudo code, it does not exist nor suggest the best possible syntax!

Case 1: Styling Legacy Content

Styling legacy content, with dated markup and structure, is a classic challenge when redesigning a website. Before HTML5, for example, an image might typically have been wrapped with a p , div , or sometimes with a span along with a nested p used to wrap the image caption. There was no standard way to wrap an image and caption. Later, we adopted the figure and figcaption elements, making our document structure more semantic.

We want the images from the legacy content to appear as above. But since there may be more div tags in our document, ones which don’t contain images at all, the following style declarations would be completely impractical.

.page-content div .img-caption  

It would apply the background color, padding and margins to all div elements in the content. We actually want to apply these styles exclusively to div elements which wrap an image and an image caption.

Case 2: Maintaining Video Ratio

Another example looks at maintaining embedded video (like from Youtube or Vimeo) ratio, as well as making the video fluid. These days, largely thanks to the investigative work by Dave Rupert and pals, it’s widely accepted that the best approach is to apply padding-top or padding-bottom to the parent element.

Youtube embed wrapped in a div

In a real world, however, we may would not know which element contains the video. We may find some embedded video wrapped within a div or a p without an identifiable class name, making it tricky to select the proper element on which to apply the styles.

Therefore, declaring the styles as follows is again impractical since it will impact all the divs within the .page-content including ones which don’t contain an embedded video.

How wonderful it would be to directly select the video’s parent element!

Case 3: Responding to Form Input

In this example we have a form with several inputs. When we focus on one of the inputs, it is given a more prominent border color, highlighting the user’s position within the form.

Sometimes you also may come across the situation where not only the border color, but the element wrapping the input is highlighted, making the input even more prominent:

The parent element might be a div or a p . So, how can we properly select the parent element based on certain states of its descendants?

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 )  

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 )  

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. Until then, take a look at the following video course entitled CSS of the Future to find out how the selector works:

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.

For example, we may use parent() to add a special class to the wrapping element of the images within the content.

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 HTML Class Added

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.

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.

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.

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.

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!

Further Resources

Источник

Parent Selection in CSS: how the CSS has selector works

CSS stands for cascading stylesheets, which basically means things later on in the page take precedence over things earlier (with some major caveats). This also applies to how we select elements — from parent to child, with no way to select parents, until now.

In the CSS Selectors 4 specification, CSS introduces a new selector called :has() , which finally lets us select parents. What that means is we’ll be able to target a CSS element which has specific children within it. This is already supported in Safari, and is also in Chrome 105. The full support table is shown below:

Data on support for the css-has feature across the major browsers from caniuse.com

With support increasing, in this article I will focus on how CSS parent selection works, and how you can do it today where support is available. In the meantime, if you require full support in all browsers, you can also implement this polyfill until native CSS support is available.

How Parent Selectors work in CSS

In CSS, if we want to select something, we use selectors that descend the DOM. For example, selecting a p tag within a div tag looks like this:

Until now, we couldn’t really select the div tags which had p tags within them, though, and this meant we had to resort to Javascript. The main reason this wasn’t implemented in CSS is because it’s quite an expensive operation to do. CSS is relatively fast to parse, but selecting parent tags requires a relatively significant larger amount of processing.

Using the :has selector, we can now select div elements which have a p children, or any normal combination of selectors. For example, selecting a div with a child p now looks like this:

/* Makes the div color: red; */ div:has(p)   color: red; > 

This will make any div with a child p red.

Combining parent selection with other selectors

Just like any other CSS selector, we can combine this for specific circumstances. For example, if you want to select only div tags which have direct span children:

As the vocabulary of :has suggests, it is not just limited to parent selection. For example, below we can select a span which :has a sibling div :

Or even, selecting an element which does not have a child, by using the :not() selector. For example, the following will select any div which does not have a p child:

Selecting elements which only contain text in CSS

One very common problem in CSS is that the :empty tag does not select elements which contain any text — so sometimes an element can contain one space, and :empty will not apply. The :has selector gives us the power to select elements which only contain text nodes, and no other child elements.

Although this is not the perfect solution for simply :empty elements with spaces (as this will select any element with just text and no additional HTML DOM elements) — it does give us the ability to select DOM elements with only text nodes, which was not previously possible. We can achieve this with the following code:

div:not(:has(*))   background: green; > 

Conclusion

With the addition of :has() selector support in Chrome 105, parent selection is quickly becoming a reality that we will soon be able to use on real life projects. As of now, with Safari support, it’s easy to test and see how it will work in the future. This has the additional benefit of letting us cut back on Javascript solutions to parent selection which is quite common in many applications and products.

You can even start using :has today, if you also implement this polyfill, and then remove the polyfill once native support comes to Chrome and other browsers.

More Tips and Tricks for CSS

Источник

Читайте также:  Javascript string method match
Оцените статью