CSS3系列-css3之线性渐变初探
qixiaoxiao
7年前
<h2>CSS3系列-css3之线性渐变初探</h2> <h2>1.写在前面</h2> <p>入行前端一年多的时间,想提高自己的css技术水平,于是在网上看了些关于css的书籍,想买几本比较好的css书籍啃啃,找来找去,终于找到了《CSS揭秘》这本书。入手这本书后,从开始看到后面,发现书中的很多效果都可以使用渐变来实现,于是,我对渐变产生了兴趣,决定好好掌握css3中的这个属性。结合 <em>《CSS揭秘》</em> 、 <em>张鑫旭</em> 大神的 <a href="/misc/goto?guid=4958984675238474094" rel="nofollow,noindex">深入理解CSS3 gradient斜向线性渐变</a> 和 <a href="/misc/goto?guid=4959756537484485940" rel="nofollow,noindex">CSS3 radial-gradient径向渐变语法及辅助理解案例10则</a> 以及其他的文章,并总结自己的学习过程,于是诞生了这篇关于css3中的渐变文章。</p> <p>渐变是是以背景图的形式呈现在页面中的, <em>渐变的本质是background-image</em> 。在css3中,渐变可以分为线性渐变(linear-gradient)和径向渐变(radial-gradient)。线性渐变是沿着渐变线进行渐变,而径向渐变则是沿着椭圆或者圆形进行四周渐变。</p> <h2>2.线性渐变linear-gradient</h2> <h3>2.1 基本语法</h3> <p>background-image: linear-gradient( [ <angle> | <side-or-corner> ,]? <color-stop> [, <color-stop>]+ );</p> <p>[] 在正则表达式中是一个字符类,这里理解为一个小单元即可;</p> <p>| 表示或者的意思,要么选择前面,要么选择后面;</p> <p>?表示0个或者1个意思。即如果不指定方向,直接可以直接使用渐变色;</p> <p>+加号, 表示1个或者多个。</p> <p>2.1.1 角度angle</p> <p>提问:如果angle是45deg,渐变颜色由 deepink 到 yellow 的渐变,请问下面哪副图是正确的?</p> <p><img src="https://simg.open-open.com/show/e0edbc84392adc122e726f7c5f3cd67a.png"></p> <p>正确答案: <strong>B</strong></p> <p>这个理解与我们所熟知的css3旋转某一个角度有一定的出入,比如,css3中旋转90度的效果是这样的:</p> <p><img src="https://simg.open-open.com/show/9da068ba410e92153428fa8bf0a1cc3a.gif"></p> <p>而在线性渐变中,渐变的角度默认是从下到上的垂直方向开始顺时针进行旋转的,我们可以理解为时钟针旋转的方向,如下图所示:</p> <p><img src="https://simg.open-open.com/show/426f65b662182684f50a776aa174ac82.png"></p> <p>渐变角度指明了线性渐变的方向,0deg表示从上向下渐变;90deg表示从左向右渐变;180deg表示从下向上渐变;270deg表示从右向左渐变;360deg表示从下向上渐变。渐变的角度效果如图所示:</p> <p><img src="https://simg.open-open.com/show/3ee82fe5b2ae5dac017123606acb1f0d.png"></p> <p>在上面的这个例子中,0deg->360deg的效果其实就是顺时针旋转一圈。</p> <p>2.1.2 side-or-corner</p> <p>side-or-corner的中文意思是边或者角的意思。在垂直方向的可选值有: top 、 center 、 bottom ,在水平方向的可选值有 left 、 center 、 right 。默认值为 <em>center bottom</em> ,即从上向下渐变。 <em>可以用to + side-or-corner关键字联合起来使用,如果不加to,则表示渐变的起始点,加上to则表示渐变的方向</em> 。例如:to top等价于0deg,to right等价于90deg,to bottom等价于180deg,to left等价于270deg。相关效果如下图所示:</p> <p><img src="https://simg.open-open.com/show/8ae75b625835655c0b96c1afd4ba0d78.png"></p> <p>不同版本浏览器中使用注意:</p> <ul> <li>新版浏览器可以直接使用w3c的标准语法,低版本浏览器需要使用各浏览器前缀;</li> <li>IE10版本以下不支持渐变;</li> <li>新版chrome和firefox已经去掉了私有前缀,加了私有前缀与不加私有前缀方向有出入(如果加了私有前缀,则right为0deg,然后逆时针转一圈);</li> <li>oper从37开始支持,没有私有前缀,加了反而不认;</li> </ul> <p>本文将以W3C标准语法讲解线性渐变 linear-gradient ,径向渐变 radial-gradient 将在下一篇文章中推出</p> <p>2.1.3 color-stop</p> <p><color> [ <percentage> | <length> ]</p> <p>指明线性渐变的颜色、起点、终点。翻译成中文就是:颜色+空格+百分比或者长度值。</p> <pre> <code class="language-css">background: linear-gradient(#fb3 20%, #58a 80%);</code></pre> <p><img src="https://simg.open-open.com/show/3ffc737badad126c211ab2d402dd206c.png"></p> <p>现在顶部20%的区域被填充为 #fb3 的实色,底部20%的区域被填充为 #58a 的实色,真正渐变的区域在20%到80%高度的区域。如果将两个色标拉近,将两个色标重合在一起:</p> <pre> <code class="language-css">background: linear-gradient(#fb3 50%, #58a 50%);</code></pre> <p><img src="https://simg.open-open.com/show/a8cf79aba9b3552fcb2f588e48186b91.png"></p> <p>“如果多个色标具有相同的位置,它们会产生一个无限小的过渡区域,过渡的起止色分别是第一个和最后一个指定值。从效果上看,颜色会在那个位置突然变化,而不是一个平滑的渐变过程。”</p> <p> ——CSS 图像(第三版)( <a href="/misc/goto?guid=4959756537579453247" rel="nofollow,noindex">http://w3.org/TR/css3-images</a> )</p> <p>因为渐变是一种由代码生成的图像,我们能像对待其他任何背景图像那样对待它,而且还可以通过background-size 来调整其尺寸:</p> <pre> <code class="language-css"><div class="box"></div></code></pre> <pre> <code class="language-css">.box{ width: 200px; height: 90px; background: linear-gradient(#fb3 50%, #58a 50%); background-size: 100% 30px; }</code></pre> <p><img src="https://simg.open-open.com/show/17f4a90459794020d7f64a8e185886c7.png"></p> <p>如果是垂直条纹,代码以及效果如下:</p> <pre> <code class="language-css"><div class="box"></div></code></pre> <pre> <code class="language-css">.box{ width: 210px; height: 90px; background: linear-gradient(to right, #fb3 50%, #58a 50%); background-size: 30px 100%; }</code></pre> <p><img src="https://simg.open-open.com/show/4b02d2e4fe3d070235b0d92a9068d4f1.png"></p> <p>为了避免每次改动条纹宽度时都要修改两个数字,我们可以再次从规范那里找到捷径。</p> <p>“如果某个色标的位置值比整个列表中在它之前的色标的位置值都要小,则该色标的位置值会被设置为它前面所有色标位置值的最大值。”</p> <p> ——CSS 图像(第三版)( <a href="/misc/goto?guid=4959756537579453247" rel="nofollow,noindex">http://w3.org/TR/css3-images</a> )</p> <p>对于水平和垂直渐变条纹我们很好理解。如果是斜向渐变,我们想得到条纹的宽度为15px,我们可以这样写:</p> <pre> <code class="language-css"><div class="box"></div></code></pre> <pre> <code class="language-css">.box{ width: 200px; height: 100px; background: linear-gradient(45deg, #fb3 25%, #58a 0, #58a 50%, #fb3 0, #fb3 75%, #58a 0); background-size: 30px 30px; }</code></pre> <p><img src="https://simg.open-open.com/show/8b95b09e3f1fa67b987432d9abca0ec4.png"></p> <p>对比想要的图以及实际效果图,为什么得到线条的宽度比我们想要的线条宽度要小,难道是浏览器出问题了,no,是我们自己错了。这就需要深入理解渐变的长度了。</p> <h3>2.2 线性渐变的渐变长度的理解</h3> <p>如何确定渐变线的长度?我们可以从官网的解释中找到答案:</p> <p><img src="https://simg.open-open.com/show/28068eeae43ac7b37003bf93aa04297e.png"></p> <p>渐变线是过渐变区域中心的一条直线,而渐变的起点和终点是在与渐变线的垂直线上。如果给定渐变的区域和渐变的方向,我们就能够确定渐变的起始点和总长度了。因此在下面的css样式中:</p> <pre> <code class="language-css">.box{ width: 200px; height: 100px; background: linear-gradient(45deg, #fb3 25%, #58a 0, #58a 50%, #fb3 0, #fb3 75%, #58a 0); background-size: 30px 30px; }</code></pre> <p>我们可以用下面的这幅图来计算渐变的长度,我们指定了区域的大小时30px,根据 勾股定理 ,可以计算直角三角形的斜边长度。因此,我们计算得到的条纹的宽度实际是: 15/1.414=10.606 ,比我们需要的宽度15p要小。</p> <p>$$ 15/√2 $$</p> <p><img src="https://simg.open-open.com/show/4e9b7e608f0f82842d1f236a1fe12fd8.png"></p> <p>这就意味着,如果想要让条纹的宽度变化为我们原本想要的15px,就需要将 background-size 指定为 2*15*1.4=42.426px 。</p> <p><img src="https://simg.open-open.com/show/25f51d69411b6ba6bdd58492b7eb8b99.png"></p> <p>我们来看下修改后的效果,修改 background-size 后,得到了我们想要的效果图。</p> <h3>2.3 线性渐变的案例</h3> <p>2.3.1 利用线性渐变生成条纹</p> <p>在上面的例子中,我们已经使用线性渐变生成了水平和垂直条纹,这里就不在赘述。</p> <p>2.3.2 利用线性渐变生成多背景图片</p> <p><em>在CSS3中,backgrounds支持多背景,越前面的背景越处于上面</em> ,也就是背景可以无限累加,而 <em>渐变的本质是background-image</em> ,所以我们可以实现任意数量的渐变背景图的叠加效果。</p> <p>有如下图片:</p> <p><img src="https://simg.open-open.com/show/a58878ccf75b71ef82175ba736364a6a.jpg"></p> <p>我们添加透明值: linear-gradient(to bottom left, #fc3, rgba(255,255,255,0))</p> <pre> <code class="language-css">.demo{ width: 250px; height: 156px; background: linear-gradient(to bottom left, #fc3, rgba(255,255,255,0)), url(./flower.jpg); }</code></pre> <p>得到的效果如下:</p> <p><img src="https://simg.open-open.com/show/221911b9f70c8a07fa7bc6e498b8a0a3.png"></p> <p>我们可以利用这一点,来给背景添加不同的效果,如让图片不可见(修改为: linear-gradient(to bottom left, #fff, rgba(255,255,255,0)) )。</p> <p>2.3.3 利用线性渐变生成比例可控的虚线</p> <p>在实际开发中,如果需要虚线,我们一般会设置 border-style:dashed ,然而这种方法存在一个问题: <em>实线和虚线的比例是一定的</em> 。在Chrome和Firefox浏览器下,颜色区的宽高比是 3:1 ,颜色和透明区的宽度比例是 1:1 :</p> <p><img src="https://simg.open-open.com/show/76f495763d72fb80486c548f84e6a473.png"></p> <p>而在IE浏览器下,颜色区的宽高比是 2:1 ,颜色区和透明区的宽度比例也是 2:1 :</p> <p><img src="https://simg.open-open.com/show/f84f86cdc8be4853c5aa0d8a6654783a.png"></p> <p>如果设计师设计的UI中,要求虚线的颜色区的宽高比是 5:3 ,实线与虚线的比例是 1:1 ,此时使用 border-style:dashed 就达不到设计师设计的效果了。有两种方法可以解决这个问题:</p> <ul> <li>要求设计师改UI,这么low X的事难道是我们前端工程师做的吗?</li> <li>查阅资料,使用其他方法实现设计师想要的效果,正确选择!</li> </ul> <p>这里,我们就可以使用 linear-gradient 到达设计师想要的效果:</p> <pre> <code class="language-css">.demo{ height: 3px; background: linear-gradient(to right, #000, #000 5px, transparent 5px, transparent); background-size: 10px 100%; }</code></pre> <p>对应的效果如下:</p> <p><img src="https://simg.open-open.com/show/07b33f7ed70e89ea3dfb223e62741d7a.png"></p> <p>2.3.4 利用线性渐变生成带线框的三角</p> <p>考虑下面的场景,我们需要生成一个对话框:</p> <p><img src="https://simg.open-open.com/show/d77644f6c08cd928051716731e65bc40.png"></p> <p>我们可能绝大多数使用下面的做法:</p> <pre> <code class="language-css">.talk { display: inline-block; max-width: 80%; border: 1px solid blue; border-radius: 3px; padding: 6px 10px; font-size: 14px; position: relative; }</code></pre> <pre> <code class="language-css">.talk:before { content: ''; position: absolute; width: 6px; height: 6px; border: 1px solid blue; border-right: 0; border-bottom: 0; left: -4px; top: 13px; transform: rotate(-45deg); background-color: #fff; }</code></pre> <p>如果背景不是白色:</p> <pre> <code class="language-css">.talk { display: inline-block; max-width: 80%; border: 1px solid blue; border-radius: 3px; padding: 6px 10px; background: linear-gradient(to right, deeppink, yellow); font-size: 14px; position: relative; }</code></pre> <p><img src="https://simg.open-open.com/show/4063b5ce5fee022c354ae41afeeb076c.png"></p> <p>可以看到如果背景色不是白色,旋转后的效果就有一个多余的三角形,不是我们想要的效果,我们可能尝试这样修改css代码:</p> <pre> <code class="language-css">.talk:before { content: ''; position: absolute; display: inline-block; width: 0; height: 0; border-top: 5px solid transparent; border-right: 5px solid blue; border-bottom: 5px solid transparent; left: -5.1px; top: 12px; }</code></pre> <p><img src="https://simg.open-open.com/show/48175c495049d9c9d10aad79214d3ce1.png"></p> <p>额,比上面的效果好多了,但是三角与边框交接的区域多了一个线条,与我们想要的效果还是有出入,此时我们使用线性渐变看看,如下css所示:</p> <pre> <code class="language-css">.talk:before { content: ""; position: absolute; width: 6px; height: 6px; background: linear-gradient(to top, blue, blue) no-repeat, linear-gradient(to right, blue, blue) no-repeat, linear-gradient(135deg, #fff, #fff 5.2px, hsla(0, 0%, 100%, 0) 5.2px) no-repeat; background-size: 60px 1px, 1px 60px, 60px 60px; transform: rotate(-45deg); left: -4px; top: 13px; }</code></pre> <p><img src="https://simg.open-open.com/show/32d811d8c274e6721bf80648a997caa1.png"></p> <p>哇,看起来不错额,今晚可以和妹子约起了。。。 <img src="https://simg.open-open.com/show/e4ed26e7e4f67c9ad3f75514e5a195ab.gif"></p> <p>2.3.5 利用线性渐变生成加号和减号</p> <p>考虑有以下需求:</p> <p><img src="https://simg.open-open.com/show/b580cac7406130df38271ee87735fd43.png"></p> <ol> <li>切图,使用小图片;</li> <li>传统方法,使用 ::before 和 ::after 伪元素配合实现;</li> <li>使用线性渐变实现;</li> </ol> <pre> <code class="language-css"><a href="javascript:" class="btn btn-plus" role="button"></a> <a href="javascript:" class="btn btn-minus" role="button"></a></code></pre> <p>传统方法:</p> <pre> <code class="language-css">.btn { display: inline-block; background: #f0f0f0 no-repeat center; border: 1px solid #d0d0d0; width: 24px; height: 24px; border-radius: 2px; color: #666; transition: color .2s; } .btn-plus{ position: relative; } .btn-plus:before{ content: ''; position: absolute; width: 10px; height: 2px; background-color: currentColor; left: 50%; top: 50%; margin-top: -1px; margin-left: -5px; } .btn-plus:after{ content: ''; position: absolute; width: 2px; height: 10px; background-color: currentColor; left: 50%; top: 50%; margin-top: -5px; margin-left: -1px; }</code></pre> <p>使用线性渐变方法:</p> <pre> <code class="language-css">.btn { display: inline-block; background: #f0f0f0 no-repeat center; border: 1px solid #d0d0d0; width: 24px; height: 24px; border-radius: 2px; color: #666; transition: color .2s; } .btn-plus { background-image: linear-gradient(to top, currentColor, currentColor), linear-gradient(to top, currentColor, currentColor); background-size: 10px 2px, 2px 10px; } .btn-minus { background-image: linear-gradient(to top, currentColor, currentColor); background-size: 10px 2px; }</code></pre> <p><img alt="【前端Talkking】CSS3系列-css3之线性渐变初探" src="https://simg.open-open.com/show/f27be4369528b077c28fe459a5792537.png"></p> <p>这种方法生成加号和等号与传统使用 ::before 和 ::after 以及配合 background-color 和 border 相比,使用渐变背景生成的好处是居中定位方便。</p> <p>2.3.6 利用线性渐变生成切角效果</p> <p>直接看代码:</p> <pre> <code class="language-css"><div class="clip"></div></code></pre> <pre> <code class="language-css">.clip{ width: 150px; height: 150px; background: #58a; background: linear-gradient(135deg, transparent 15px, deeppink 0) top left, linear-gradient(-135deg, transparent 15px, yellow 0) top right, linear-gradient(-45deg, transparent 15px, blue 0) bottom right, linear-gradient(45deg, transparent 15px, green 0) bottom left; background-size: 50% 50%; background-repeat: no-repeat; }</code></pre> <p><img src="https://simg.open-open.com/show/784d5a04b7410a2b42a0319d6c1c81b3.png"></p> <p>利用线性渐变还可以实现折角效果(计算稍微复杂,详细计算步骤可以看《css揭秘》相关章节),如:</p> <p><img src="https://simg.open-open.com/show/2820389749addda1aa7b5ad94fad7d07.png"></p> <p>2.3.7 利用线性渐变实现信封效果</p> <pre> <code class="language-css"><div class="demo2">重复渐变实现信封效果</div></code></pre> <pre> <code class="language-css">.demo2{ width: 300px; font-size: 18px; padding: 10px; border: 10px solid transparent; background: linear-gradient(white, white) padding-box, repeating-linear-gradient(-45deg, red 0, red 12.5%, transparent 0, transparent 25%, #58a 0, #58a 37.5%, transparent 0, transparent 50%) 0 / 60px 60px; }</code></pre> <p><img src="https://simg.open-open.com/show/2f15fd9ee23f24a964cdf9766a3cf934.png"></p> <p>2.3.8 利用线性渐变实现裁剪效果</p> <pre> <code class="language-css"><div class="clip">这里是文字</div></code></pre> <pre> <code class="language-css">.clip{ padding: 1em; border: 10px solid transparent; background: linear-gradient(white, white) padding-box, repeating-linear-gradient(-45deg, black 0, black 25%, transparent 0, transparent 50%) 0 / 10px 10px; animation: ants 12s linear infinite; max-width: 20em; } @keyframes ants { from { background-position: 0 0; } to { background-position: 100% 100%; } }</code></pre> <p>在浏览器中的效果如下:</p> <p><img src="https://simg.open-open.com/show/d9ee0707d031f4cf849b9d9bfefeb2a0.gif"></p> <p>如果将 boder 修改为 1px solid transparent ,可以看到下面的效果:</p> <p><img src="https://simg.open-open.com/show/3ae181f46f0d3d8b5275ca708ece7d2e.gif"></p> <h3>2.4 更多线性渐变的应用</h3> <p>更多关于线性渐变的应用可以查看 <a href="/misc/goto?guid=4958338173654431759" rel="nofollow,noindex">这里</a></p> <p>这里的图形都是使用线性渐变实现的,可见CSS3中线性渐变功能之强大!</p> <p><img src="https://simg.open-open.com/show/4ce10f7021610506aa9a9eb22ebef0cd.png"></p> <h2>4 更多关于线性渐变的东西</h2> <p>除了线性渐变 linear-gradient ,css3中还支持重复线性渐变 reapting-linear-gradient 。</p> <ul> <li> <p>利用重复线性渐变实现斜向条纹的效果,与线性渐变相比,不需要苦苦思考生成一个重复单元,直接改变渐变的角度以及尺寸即可。</p> <pre> <code class="language-css">background: repeating-linear-gradient(60deg,#fb3, #fb3 15px, #58a 0, #58a 30px);</code></pre> <p></p> </li> </ul> <p><img src="https://simg.open-open.com/show/e9e101375c711a903e3e0e4b4b7e799f.png"></p> <h2>5 写在最后</h2> <p>如果想对提高自己的csss水平,推荐《CSS揭秘》,很不错额。</p> <p><img src="https://simg.open-open.com/show/c29ec87287a43860b5f5db28ff94a152.png"></p> <p>感谢阅读。</p> <h2>6 参考链接</h2> <p><a href="/misc/goto?guid=4959756537709798871" rel="nofollow,noindex">W3C linear-gradient</a></p> <p><a href="/misc/goto?guid=4958984675238474094" rel="nofollow,noindex">深入理解CSS3 gradient斜向线性渐变</a></p> <p><a href="/misc/goto?guid=4959756537484485940" rel="nofollow,noindex">CSS3 gradient介绍</a></p> <p>遇见了,不妨关注下我的微信公众号「前端Talkking」</p> <p><img src="https://simg.open-open.com/show/927c02b182a3144bb31f1d72f0ec487b.png"></p> <p> </p> <p>来自:https://segmentfault.com/a/1190000012882599</p> <p> </p>