Clever use :has & drop-shadow to achieve complex layout effects

Posted: 2024-04-18 15:28:45 Author: Anonymous I want to comment
I don't have a clear emotional understanding of all the CSS properties. I have only been using CSS for a few years and I still have a lot to learn. However, I still have a feeling for the common float properties in CSS

Recently, the group talked about a very interesting layout effect. The general effect is as follows. You want to use CSS to achieve the following layout effect:

Normally, our HTML structure looks something like this:

<div class="g-container"> <div class="g-nav"> <ul> <li>Tab 1</li> <li>Tab 2</li> <li>Tab 3</li> <li>Tab 4</li> </ul> </div> <div class="g-main"> <ul class="g-content"> <li>... </li> <li>... </li> <li>... </li> <li>... </li> </ul> </div> </div>

For Hover navigation Tab when the content switch, let's not talk about. In this paper, we want to discuss the core of two points:

One is how to implement an irregular layout as shown below:

And, here we may also need to add a shadow effect:

How to cooperate with Hover action to achieve the whole switching effect

With these two questions in mind, let's try to achieve this effect slowly.

Implement irregular buttons with pseudo-elements

First, we need to achieve this effect:

This, in fact, has been mentioned in many articles:

Think about it, this is what vertical Chrome Tab looks like:

Like this:

Let's disassemble the shape of this button, and it's actually a superposition of 3 pieces:

You just need to figure out how to achieve the curved triangle on both sides. Here again with the help of gradient - radial gradient, in fact, it is like this, as shown below, we only need to replace the black part with transparent can use two pseudo-elements can:

The code is as follows:

<div class="outside-circle"></div>
.outside-circle { position: relative; background: #e91e63; border-radius: 10px 10px 0 0; &::before { content: ""; position: absolute; width: 20px; height: 20px; left: -20px; bottom: 0; background: #000; background:radial-gradient(circle at 0 0, transparent 20px, #e91e63 21px); } &::after { content: ""; position: absolute; width: 20px; height: 20px; right: -20px; bottom: 0; background: #000; background:radial-gradient(circle at 100% 0, transparent 20px, #e91e63 21px); }}

You can get:

We can achieve the same vertical effect very easily, as shown in the following diagram:

Use drop-shadow for button shading

Ok, next, we need to add a shadow effect to the button, like this:

Because two pseudo-elements are used, the approximate code for the current single button in the Hover state is as follows:

li { position: relative; width: 160px; height: 36px; border-radius: 10px 0 0 10px; background: #ddd; &::before, &::after { content: ""; position: absolute; right: 0; border-radius: unset; } &::before { width: 20px; height: 20px; top: -20px; background: radial-gradient(circle at 0 0, transparent, transparent 19.5px, #ddd 20px, #ddd); } &::after { width: 20px; height: 20px; bottom: -20px; background: radial-gradient(circle at 0 100%, transparent, transparent 19.5px, #ddd 20px, #ddd); }}

If you use box-shadow, it will definitely not work, and the entire effect will be revealed:

Try adding a box-shadow: 0 0 5px 0 #333:

Curved joint, obviously no shadow effect, how to solve it?

As regular readers will know, here we need to add a shadow to the entire visible part, using filter:drop-shadow().

The role of the drop-shadow() filter is to create a shadow that matches the shape (alpha channel) of the element (image) itself. Among them, the most common technique is to use it to generate irregular shadows.

Therefore, we replace the box-shadow above with: filter: drop-shadow(0 0 5px #ddd) :

In this way, we achieve a shadow effect based on a single irregular button.

But, apparently, it's not over yet.

Modify the layout structure and use drop-shadow to achieve a unified shadow

Remember the HTML layout we mentioned above? Normally, the structure of the body content on the right and the navigation on the left is separate:

<div class="g-container"> <div class="g-nav"> <ul> <li>Tab 1</li> // ... </ul> </div> <div class="g-main"> <ul class="g-content"> <li>... </li> // ... </ul> </div> </div>

Therefore, the most troublesome place here is that the shadow of the left button needs to be connected with the main content on the right! So when we add the same filter:drop-shadow() to.g-main on the right, the whole effect gets really weird:

// The current Hover Li.g-nav li {filter: drop-shadow(0 0 5px #ddd)} // The right body.g-main {filter: drop-shadow(0 0 5px #ddd)}

No matter who is on the hierarchy, the presentation of the overall shadow will be flawed:

Therefore, if we want to achieve the effect that the shadow of the whole element is a whole whole, we have to find a different way.

Here, our thinking is as follows:

  • You can try in.g-mainIn, add a group with.g-navThe same structure is responsible for the presentation of the style level
  • Take the new structure and use absolute positioning to overlap with the actual navigation position
  • In the original.g-navIn, through:has()Pseudo-classes that pass real-time Hover state

Based on this, we need to revamp our structure:

<div class="g-container"> <div class="g-nav"> <ul> <li>Tab 1</li> <li>Tab 2</li> <li>Tab 3</li> <li>Tab 4</li> </ul> </div> <div class="g-main"> <ul class="g-status"> <li></li> <li></li> <li></li> <li></li> </ul> <ul class="g-content"> <li>... </li> // ... </ul> </div> </div>

Looking carefully at the structure above, we have added a set of.g-stauts structures, placed under.g-main. The number of li is consistent with the actual navigation.g-nav, and the height, width and size are exactly the same.

Moreover, absolute positioning can be used to superimpose it completely on the position of.g-nav.

We then assign the above CSS code structure like the Chrome tab-style irregular button structure to li under.g-status.

At this time, because the irregular button structure and the body content structure on the right side are actually under a parent div, we only need to add filter: drop-shadow() to the.g-main element, and we can achieve a whole shadow effect:

Finally, we use the :has() pseudo-class to pass the real-time Hover state and connect the structures inside and outside.

The most core code is as follows:

.g-main { background: #ddd; filter: drop-shadow(0 0 3px #999); } .g-status { position:absolute; left: -160px; top: 0; width: 160px; li { width: 160px; height: 36px; position: relative; background: #ddd; opacity:0; &::before, &::after { content: ""; position: absolute; right: 0; border-radius: unset; } &::before { width: 20px; height: 20px; top: -20px; background: radial-gradient(circle at 0 0, transparent, transparent 19.5px, #ddd 20px, #ddd); } &::after { width: 20px; height: 20px; bottom: -20px; background: radial-gradient(circle at 0 100%, transparent, transparent 19.5px, #ddd 20px, #ddd); } } } .g-status li { opacity: 0; } .g-nav:has(li:nth-child(1):hover) + .g-main { .g-status li:nth-child(1) { opacity: 1; } } .g-nav:has(li:nth-child(2):hover) + .g-main { .g-status li:nth-child(2) { opacity: 1; } } .g-nav:has(li:nth-child(3):hover) + .g-main { .g-status li:nth-child(3) { opacity: 1; } } .g-nav:has(li:nth-child(4):hover) + .g-main { .g-status li:nth-child(4) { opacity: 1; }}

What does that mean? To explain:

  • I've written the style for each Tab to Hover.g-stautsAnd again, as a reminder, this structure is in.g-mainThe one below. Then, the default setting can be hidden;
  • The actual trigger Hover animation effect is normal.g-navThe next one by one li structure;
  • when.g-navWhen the next li is Hover, we pass:has()Pseudo-class, can get this event, and depending on how many elements are currently hover, the corresponding control is actually in.g-mainUnder the structure of the style display;

Less familiar :has() pseudo-class friends, you can read this article first - talk about the logic selector is, where, not, has, the birth of this pseudo-class, to fill in the previous CSS selector, there is no parent selector vacancy. Allows us to make style adjustments on the parent element node, based on the state changes of the child element.

In this way, we have finally achieved the effect that our article started with:

The article may have part of the content is not stated very clearly, the complete code its implementation number is very small, the content of the article is not very understanding of the suggestion to poke into the DEMO.

Full DEMO Effect: CodePen Demo -- Tab Hover Effect

Some small partners will have questions, why not directly in the.g-nav navigation structure and.g-main structure of the parent node directly add drop-shadow(), not can also achieve the same effect?

Yes, the same effect can be achieved for the code effects posted in this article. However, in real business,.g-NAV is more complex, and there may be other elements under their common parent, which is far more complex than the structure posted in this article, so using an extra layer of virtual ul is actually a better solution.

To this article on clever use :has &amp; amp; drop-shadow to achieve complex layout effects of the article is introduced to this, more related to the drop-shadow complex layout content please search script home previous articles or continue to browse the following related articles, I hope you will support the script home in the future!

  • Tag: has layout drop-shadow

Related article

Latest comments