广告位联系
返回顶部
分享到

巧用 :has & drop-shadow实现复杂布局效果

css 来源:互联网 作者:佚名 发布时间:2024-04-19 22:37:05 人浏览
摘要

最近,群里聊到了一个很有意思的布局效果。大致效果如下所示,希望使用 CSS 实现如下所示的布局效果: 正常而言,我们的 HTML 结构大致是如下所示: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 div

最近,群里聊到了一个很有意思的布局效果。大致效果如下所示,希望使用 CSS 实现如下所示的布局效果:

正常而言,我们的 HTML 结构大致是如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<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>

对于 Hover 导航 Tab 时候的内容切换,暂且不谈。本文,我们核心想探讨的是两个点:

一是对于如下所示的不规则布局,应该如何实现:

并且,这里我们可能还需要给它加上阴影效果:

如何配合 Hover 动作,实现整个切换效果

带着这两个问题,我们一起来尝试慢慢把这个效果实现。

借助伪元素实现不规则按钮

首先,我们需要实现这个效果:

这个,其实在很多篇文章都有提及过:

  • 由小见大!不规则造型按钮解决方案
  • 使用 CSS 轻松实现高频出现的各类奇形怪状按钮

想一想,这里其实就是竖向的 Chrome 分 Tab 的效果:

像是这样:

我们对这个按钮形状拆解一下,这里其实是 3 块的叠加:

只需要想清楚如何实现两侧的弧形三角即可。这里还是借助了渐变 -- 径向渐变,其实他是这样,如下图所示,我们只需要把黑色部分替换为透明即可,使用两个伪元素即可:

代码如下:

1

<div class="outside-circle"></div>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

.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);

    }

}

即可得到:

我们照葫芦画瓢,即可非常轻松的实现竖向的相同的效果,示意图如下:

利用 drop-shadow 实现按钮阴影

好,接下来,我们需要给按钮添加上阴影效果,像是这样:

因为使用了两个伪元素,当前单个按钮在 Hover 状态下的大致代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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);

    }

}

如果使用 box-shadow 肯定是不行的,整个效果就会露馅:

尝试给按钮添加一个 box-shadow: 0 0 5px 0 #333:

弯曲的连接处,明显没有阴影效果,怎么解决呢?

嗯哼,老读者一定也知道,这里我们需要对整个可见部分添加阴影,需要使用 filter:drop-shadow()。

drop-shadow()滤镜的作用用于创建一个符合元素(图像)本身形状(alpha 通道)的阴影。其中,最为常见的技巧,就是利用它生成不规则图形的阴影。

因此,我们把上述的 box-shadow 替换成:filter: drop-shadow(0 0 5px #ddd):

这样,我们就实现了基于单个不规则按钮的阴影效果。

但是,显然事情还没有结束。

修改布局结构,再借助利用 drop-shadow 实现统一阴影

记得我们上面提到过的 HTML 的布局吗?正常而言,右侧的主体内容和左侧的导航,结构是分离的:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

<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>

因此,这里最为麻烦的地方在于,左侧按钮的阴影,需要和右侧的主体内容连在一起!,所以当我们给右侧的 .g-main 也添加上相同的 filter:drop-shadow() 时,整个效果会变得非常奇怪:

1

2

3

4

5

6

7

8

// 当前被 Hover 的 li

.g-nav li {

    filter: drop-shadow(0 0 5px #ddd)

}

// 右侧的主体

.g-main {

    filter: drop-shadow(0 0 5px #ddd)

}

无论层级谁在上,整体阴影的展示都会瑕疵:

所以,如果想要实现整个元素的阴影是一整个的整体的效果,我们就不得不另辟蹊径。

这里,我们的思路如下:

  • 可以尝试在 .g-main 中,添加一组与 .g-nav 相同的结构,负责样式层面的展示
  • 把新增的结构,利用绝对定位,让其与实际的导航位置重叠
  • 在原本的 .g-nav 中,通过 :has() 伪类,传递实时的 Hover 状态

基于此,我们需要改造一下我们的结构:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

<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>

仔细看上面的结构,我们多了一组 .g-stauts 结构,放置在了 .g-main 之下。其 li 个数与实际的导航 .g-nav 保持一致,并且高宽大小都是一模一样的。

并且,可以利用绝对定位,让其完全叠加在 .g-nav 的位置上。

然后,我们把上述类 Chrome Tab 样式的不规则按钮结构的 CSS 代码结构,都赋给 .g-status 下的 li。

此时,由于不规则按钮结构和右侧的主体内容结构,其实是在一个父 div 之下,所以,我们只需要给 .g-main 元素添加 filter: drop-shadow(),就可以实现一整个整体的阴影效果:

最后,我们利用 :has() 伪类,传递实时的 Hover 状态,把内外的结构连接起来。

最为核心的代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

.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;

    }

}

什么意思呢?解释一下:

  • 事先把每一个 Tab 被 Hover 时的样式,都写在了 .g-stauts 中,并且再提醒一下,这个结构是在 .g-main 之下的。然后,默认设置隐藏即可;
  • 实际触发 Hover 动画效果,是正常的 .g-nav 下的一个一个的 li 结构;
  • 当 .g-nav 下的一个一个的 li 被 Hover 时,我们通过 :has() 伪类,能够拿到此事件,并且根据当前是第几个元素被 hover,对应的控制实际在 .g-main 下的结构进行样式的展示;

不太了解的 :has() 伪类的小伙伴,可以先读一读这篇文章 -- 浅谈逻辑选择器 is、where、not、has,此伪类的诞生,填补了在之前 CSS 选择器中,没有父选择器的空缺。让我们能够在父元素节点上,根据子元素的状态变化,做出样式的调整。

这样,我们就最终实现了我们文章一开始的效果:

文章可能有部分内容没有阐述的很清晰,完整的代码其实行数非常之少,对文章内容还不太理解的建议戳进 DEMO 中看看。

完整的 DEMO 效果:CodePen Demo -- Tab Hover Effect

有小伙伴会有疑问,为什么不直接在 .g-nav 导航结构和 .g-main 结构的父节点直接添加 drop-shadow(),不是也可以实现一样的效果吗?

是的,对于本文贴出的代码效果,是可以实现一样的效果。但是,实际业务中,.g-nav 会更复杂,它们的共同父元素下也可能还有其他元素,实际情况远比本文贴出来的结构复杂,因此借助多一层虚拟 ul,实际上是更好的解法。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
    Tag :
相关文章
  • css3 iphone玻璃透明气泡完美实现

    css3 iphone玻璃透明气泡完美实现
    最近在一个私活做手机项目时候,需要实现一个类似ios 6中短信那样的气泡效果。 这里分享下实现心得,希望能给大家一点启发。 首先分析
  • 巧用 :has & drop-shadow实现复杂布局效果

    巧用 :has & drop-shadow实现复杂布局效果
    最近,群里聊到了一个很有意思的布局效果。大致效果如下所示,希望使用 CSS 实现如下所示的布局效果: 正常而言,我们的 HTML 结构大致
  • 纯CSS实现多标签自动显示超出数量的思路介绍·

    纯CSS实现多标签自动显示超出数量的思路介绍·
    css实现:有多个宽度不同的标签水平排列,当外层宽度不足时,会自动提示超出的数量 实现思路 CSS 如何动态累计数字? 利用 CSS计数器 1
  • CSS设置水平垂直居中的7种方法总结

    CSS设置水平垂直居中的7种方法总结
    1. 水平居中 - 文本或行内元素 使用 text-align 属性 1 2 3 .parent { text-align: center; /* 子元素如果是内联或内联块元素,将会水平居中 */ } 1 2 3 4
  • CSS设置背景模糊周边有白色光晕(解决方案)
    css设置背景模糊周边有白色光晕,如何解决? 1 2 3 4 div class=img-box img :src=xxx.png div class=img-bg :style={background-image: `url(`+ xxx.png+ `)`}/div /div 1 2
  • CSS实现渐变式圆点加载动画

    CSS实现渐变式圆点加载动画
    知识点: animation 时间函数 steps()。 用 css3 模拟一个渐变式圆点加载效果。 核心代码部分,简要说明了写法思路;完整代码在最后,可直接
  • html table+css实现可编辑表格的代码

    html table+css实现可编辑表格的代码
    要实现可编辑的 HTML 表格,你可以使用 JavaScript 和 HTML5 的 contenteditable 属性。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
  • CSS实现三栏布局的四种方法介绍

    CSS实现三栏布局的四种方法介绍
    1. 什么是三栏布局 常见的一种页面布局方式,将页面分为左栏、中栏和右栏 左右两侧的盒子宽度固定,中间的盒子会随屏幕自适应 一般中
  • CSS中隐藏元素的常见5种方法总结

    CSS中隐藏元素的常见5种方法总结
    在CSS中隐藏元素有多种方法,下面列出几种常见方法及其适用场景与区别: 1. display: none 1 2 3 .element-to-hide { display: none; } 适用场景:完全隐
  • CSS设置style属性的3种方法介绍

    CSS设置style属性的3种方法介绍
    可以将css样式编写到元素的style属性当中: 1.将样式直接写到style属性中,这种样式我们称为内联样式,内联样式只对当前的元素中的内容起
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计