几种常见的CSS布局

本文概要本文将介绍如下几种常见的布局:单列布局两列自适应布局圣飞布局和双飞翼布局伪等高布局粘连布局一、单列布局常见的单列布局有两种:header,content和footer等宽的单列布局header与footer等宽,content略窄的单列布局1.如何实现对于第一种,先通过对header,content,footer统一设置width:1000px;或者max-width:1000px(这两者的区别是当屏幕小于1000px时,前者会出现滚动条,后者则不会,显示出实际宽度);然后设置margin:auto实现居中即可得到。<div class=“header”></div><div class=“content”></div><div class=“footer”></div>.header{ margin:0 auto; max-width: 960px; height:100px; background-color: blue;}.content{ margin: 0 auto; max-width: 960px; height: 400px; background-color: aquamarine;}.footer{ margin: 0 auto; max-width: 960px; height: 100px; background-color: aqua;}对于第二种,header、footer的内容宽度不设置,块级元素充满整个屏幕,但header、content和footer的内容区设置同一个width,并通过margin:auto实现居中。<div class=“header”> <div class=“nav”></div></div><div class=“content”></div><div class=“footer”></div>.header{ margin:0 auto; max-width: 960px; height:100px; background-color: blue;}.nav{ margin: 0 auto; max-width: 800px; background-color: darkgray; height: 50px;}.content{ margin: 0 auto; max-width: 800px; height: 400px; background-color: aquamarine;}.footer{ margin: 0 auto; max-width: 960px; height: 100px; background-color: aqua;}二、两列自适应布局两列自适应布局是指一列由内容撑开,另一列撑满剩余宽度的布局方式1.float+overflow:hidden如果是普通的两列布局,浮动+普通元素的margin便可以实现,但如果是自适应的两列布局,利用float+overflow:hidden便可以实现,这种办法主要通过overflow触发BFC,而BFC不会重叠浮动元素。由于设置overflow:hidden并不会触发IE6-浏览器的haslayout属性,所以需要设置zoom:1来兼容IE6-浏览器。具体代码如下:<div class=“parent” style=“background-color: lightgrey;"> <div class=“left” style=“background-color: lightblue;"> <p>left</p> </div> <div class=“right” style=“background-color: lightgreen;"> <p>right</p> <p>right</p> </div> </div>.parent { overflow: hidden; zoom: 1;}.left { float: left; margin-right: 20px;}.right { overflow: hidden; zoom: 1;}注意点:如果侧边栏在右边时,注意渲染顺序。即在HTML中,先写侧边栏后写主内容2.Flex布局Flex布局,也叫弹性盒子布局,区区简单几行代码就可以实现各种页面的的布局。//html部分同上.parent { display:flex;} .right { margin-left:20px; flex:1;}3.grid布局Grid布局,是一个基于网格的二维布局系统,目的是用来优化用户界面设计。//html部分同上.parent { display:grid; grid-template-columns:auto 1fr; grid-gap:20px} 三、三栏布局特征:中间列自适应宽度,旁边两侧固定宽度,实现三栏布局有多种方式(可以猛戳实现三栏布局的几种方法),本文着重介绍圣杯布局和双飞翼布局。1.圣杯布局① 特点比较特殊的三栏布局,同样也是两边固定宽度,中间自适应,唯一区别是dom结构必须是先写中间列部分,这样实现中间列可以优先加载。 .container { padding-left: 220px;//为左右栏腾出空间 padding-right: 220px; } .left { float: left; width: 200px; height: 400px; background: red; margin-left: -100%; position: relative; left: -220px; } .center { float: left; width: 100%; height: 500px; background: yellow; } .right { float: left; width: 200px; height: 400px; background: blue; margin-left: -200px; position: relative; right: -220px; } <article class=“container”> <div class=“center”> <h2>圣杯布局</h2> </div> <div class=“left”></div> <div class=“right”></div> </article>② 实现步骤三个部分都设定为左浮动,否则左右两边内容上不去,就不可能与中间列同一行。然后设置center的宽度为100%(实现中间列内容自适应),此时,left和right部分会跳到下一行通过设置margin-left为负值让left和right部分回到与center部分同一行通过设置父容器的padding-left和padding-right,让左右两边留出间隙。通过设置相对定位,让left和right部分移动到两边。③ 缺点center部分的最小宽度不能小于left部分的宽度,否则会left部分掉到下一行如果其中一列内容高度拉长(如下图),其他两列的背景并不会自动填充。(借助伪等高布局可解决)④ 伪等高布局等高布局是指子元素在父元素中高度相等的布局方式。等高布局的实现包括伪等高和真等高,伪等高只是看上去等高而已,真等高是实实在在的等高。此处我们通过伪等布局便可解决圣杯布局的第二点缺点,因为背景是在padding区域显示的,设置一个大数值的padding-bottom,再设置相同数值的负的margin-bottom,并在所有列外面加上一个容器,并设置overflow:hidden把溢出背景切掉。这种可能实现多列等高布局,并且也能实现列与列之间分隔线效果,结构简单,兼容所有浏览器。新增代码如下: .center, .left, .right { padding-bottom: 10000px; margin-bottom: -10000px; } .container { padding-left: 220px; padding-right: 220px; overflow: hidden;//把溢出背景切掉 }2.双飞翼布局① 特点同样也是三栏布局,在圣杯布局基础上进一步优化,解决了圣杯布局错乱问题,实现了内容与布局的分离。而且任何一栏都可以是最高栏,不会出问题。 .container { min-width: 600px;//确保中间内容可以显示出来,两倍left宽+right宽 } .left { float: left; width: 200px; height: 400px; background: red; margin-left: -100%; } .center { float: left; width: 100%; height: 500px; background: yellow; } .center .inner { margin: 0 200px; //新增部分 } .right { float: left; width: 200px; height: 400px; background: blue; margin-left: -200px; } <article class=“container”> <div class=“center”> <div class=“inner”>双飞翼布局</div> </div> <div class=“left”></div> <div class=“right”></div> </article>② 实现步骤(前两步与圣杯布局一样)三个部分都设定为左浮动,然后设置center的宽度为100%,此时,left和right部分会跳到下一行;通过设置margin-left为负值让left和right部分回到与center部分同一行;center部分增加一个内层div,并设margin: 0 200px;③ 缺点多加一层 dom 树节点,增加渲染树生成的计算量。3.两种布局实现方式对比:两种布局方式都是把主列放在文档流最前面,使主列优先加载。两种布局方式在实现上也有相同之处,都是让三列浮动,然后通过负外边距形成三列布局。两种布局方式的不同之处在于如何处理中间主列的位置:圣杯布局是利用父容器的左、右内边距+两个从列相对定位;双飞翼布局是把主列嵌套在一个新的父级块中利用主列的左、右外边距进行布局调整四、粘连布局1.特点有一块内容<main>,当<main>的高康足够长的时候,紧跟在<main>后面的元素<footer>会跟在<main>元素的后面。当<main>元素比较短的时候(比如小于屏幕的高度),我们期望这个<footer>元素能够“粘连”在屏幕的底部当main足够长时当main比较短时具体代码如下: <div id=“wrap”> <div class=“main”> main <br /> main <br /> main <br /> </div> </div> <div id=“footer”>footer</div> * { margin: 0; padding: 0; } html, body { height: 100%;//高度一层层继承下来 } #wrap { min-height: 100%; background: pink; text-align: center; overflow: hidden; } #wrap .main { padding-bottom: 50px; } #footer { height: 50px; line-height: 50px; background: deeppink; text-align: center; margin-top: -50px; }2.实现步骤(1)footer必须是一个独立的结构,与wrap没有任何嵌套关系(2)wrap区域的高度通过设置min-height,变为视口高度(3)footer要使用margin为负来确定自己的位置(4)在main区域需要设置 padding-bottom。这也是为了防止负 margin 导致 footer 覆盖任何实际内容。如果觉得文章对你有些许帮助,欢迎在我的GitHub博客点赞和关注,感激不尽!参考文章双飞翼布局介绍-始于淘宝UEDCSS三栏布局的四种方法CSS 两列布局—左侧固定,右侧自适应两列自适应布局的四种思路css常见布局之九:三栏布局的常见实现【布局】聊聊为什么淘宝要提出「双飞翼」布局CSS的单列布局与二&三列布局 ...

November 9, 2018 · 2 min · jiezi

网页中默认图片的几种解决方式

现在网页中图片随处可见,但避免不了有时会出现图片资源失败的情况,在谷歌浏览器中就会显示这样<img src=“logo.jpg” alt=“logo”>这里的alt属性是为了当图片加载失败时告诉用户图片信息的能不能美化一下呢?下面给出几种方式js 方式相信大家碰到这种问题是,搜索的结果一般都是用图片的onerror方法onerror 事件会在文档或图像加载过程中发生错误时被触发。在装载文档或图像的过程中如果发生了错误,就会调用该事件句柄。使用方式也很简单<img src=“logo.jpg” alt=“logo” onerror=“this.src=‘https://xxx.img/logo.png'">但是,这个方法一定要注意,保证onerror里面赋值的图片地址一定不能出错,否则,就会无限调用onerror…页面直接崩掉..有人说,我可以保证呀。那么,既然能保证,为什么还会有前面图片加载失败,而启用备用图片的情况发生呢?当然,你可以采用base64的方式,缺点就是太长..类似下面这种<img src=“logo.jpg” alt=“logo” onerror=“this.src=‘data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZu…IIggggCCKAIIgAgiACCIIIIAgigCCIAIIgAgiCCCAIIoAgiACCIAIIQm7xfwIMAADDZPsh5DI6AAAAAElFTkSuQmCC’">兼容性还是可以的,基本满足日常开发。那么有没有css解决方式呢?当然有,如果只用兼容主流浏览器的话css 方式这里提供两种方式伪元素虽然img是单标签<img>,里面不能包裹其他元素,但是却可以包含伪元素不过这里有个特征,只有当图片加载失败或者没有图片的时候,才会显示伪元素既然如此,我们可以用伪元素来实现一个默认提示效果img{ display: inline-block; position: relative; width: 200px; height: 200px; background: #ccc; vertical-align: top;}img:after{ content: ‘’; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: url(‘img/b.jpg’) #ccc;}思路很简单,就是用伪元素覆盖在原图片上,而且图片加载失败也没什么问题,最多不显示,也可以以纯色背景作为默认占位图。背景图片还有一种方式,用到了css3中的多背景特性div{ background:url(a.jpg), url(b.jpg), url(logo.png);}指定的时候,按浏览器中显示时图像叠放的顺序从上往下指定的,第一个图像文件是放在最上面的,最后指定的文件是放在最下面的。这样我们也可以实现默认图片的显示.img{ width: 200px; height: 200px; background: url(‘a.png’),url(’logo.png’) #f1f1f1}不过这种方式本质上是多张图片重叠在一起,如果上一层加载失败,才会看得见底下的那一张,也就是说如果都加载成功,其实都是存在的。那么就要主要了,如果上层的图有透明部分,就有可能看得到底下的图,漏光了!如上,两张图都加载成功了,由于上层有透明部分,所以看到了底图。所以在使用这种情况的时候,需要使用.jpg图片,避免走光小节以上介绍了三种设置默认图片的方式,从兼容性方面来讲,js方法适应性最广,可以低版本兼容ie,其他两种就不行了,只需注意备用图片地址不要出错就可以了个人比较建议第二种伪元素方式,纯css方式,html可以不做任何修改,适合对已有项目的体验升级,有了体验更好,没有也无伤大雅第三种就可以当娱乐看看了,当做一种思维方式吧,毕竟没有任何语义化,给一个div,别人根本就不知道这是一张图片,对搜索引擎也不友好。各位小伙伴还有什么更好的方式呢? ^^大家如果喜欢我的博客,可以多多关注一下

October 30, 2018 · 1 min · jiezi

前端每日实战:161# 视频演示如何用纯 CSS 创作一张纪念卓别林的卡片(没有笑声的一天就是被荒废的一天)

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/WaaBNV可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/c3DQeC7源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含的 3 个元素分别代表帽子、胡须和手杖:<figure class=“chaplin”> <span class=“hat”></span> <span class=“beard”></span> <span class=“stick”></span></figure>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center;}定义容器尺寸,并设置子元素水平居中:.chaplin { width: 40em; height: 30em; font-size: 10px; background-color: #eee; box-shadow: 0 0 3em rgba(0, 0, 0, 0.2); display: flex; flex-direction: column; align-items: center;}定义默认颜色,后面用 currentColor 引用此颜色:.chaplin { color: #555;}画出帽子的轮廓:.chaplin { position: relative;}.hat { position: absolute; width: 6.4em; height: 4.6em; background-color: currentColor; border-radius: 2.3em 2.3em 0 0; top: 1.4em;}用伪元素画出帽沿:.hat::before { content: ‘’; position: absolute; width: 10em; height: 0.8em; background-color: currentColor; border-radius: 0.4em; top: calc(100% + 0.4em); left: calc((100% - 10em) / 2);}画出胡子:.beard { position: absolute; width: 1.5em; height: 0; top: 11.6em; border: solid transparent; border-width: 0 0.4em 1em 0.4em; border-bottom-color: currentColor;}画出手杖的杖杆:.stick { position: absolute; width: 0.8em; height: 10.5em; background-color: currentColor; bottom: 0;}用 ::before 伪元素画出手杖的握柄:.stick::before { content: ‘’; position: absolute; box-sizing: border-box; width: 5.6em; height: 3em; border: 0.8em solid; border-radius: 5.6em 5.6em 0 0; border-bottom: none; top: -3em;}用 ::after 伪元素修饰握柄的端点,使其圆润自然:.stick::after { content: ‘’; position: absolute; width: 0.8em; height: 0.8em; background-color: currentColor; border-radius: 50%; left: calc(5.6em - 0.8em); top: -0.4em;}使手杖水平居中:.stick { left: calc((100% - (5.6em - 0.8em)) / 2);}至此,抽象的卓别林形象完成,接下来排版一句他的名言。在 dom 中增加一个 .quote 元素,并把一句话分为 3 段:<figure class=“chaplin”> <span class=“hat”></span> <span class=“beard”></span> <span class=“stick”></span> <p class=“quote”> <span>a day without</span> <span>laughter</span> <span>is a day wasted</span> </p></figure>定位文字,并竖排 3 段文字:.quote { position: absolute; left: 50%; bottom: 2.5em; font-family: sans-serif; text-transform: uppercase; font-weight: bold; display: flex; flex-direction: column;}调整字号和字间距,使 3 段文字对齐:.quote span:nth-child(1) { letter-spacing: 0.05em;}.quote span:nth-child(2) { font-size: 1.6em;}大功告成! ...

October 25, 2018 · 2 min · jiezi

前端每日实战:160# 视频演示如何用纯 CSS 创作一个打开内容弹窗的交互动画

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/GYXvez可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cNzVnAL源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,一个名为 .main 的容器中包含 1 个链接:<div class=“main”> <a href="#" class=“open-popup”>open popup</a></div>设置页面的基本属性:无边距、全高、忽略溢出:body { margin: 0; height: 100vh; overflow: hidden;}设置主界面的背景和其中按钮的布局方式:.main { height: inherit; background: linear-gradient(dodgerblue, darkblue); display: flex; align-items: center; justify-content: center;}设置按钮样式:.open-popup { box-sizing: border-box; color: white; font-size: 16px; font-family: sans-serif; width: 10em; height: 4em; border: 1px solid; text-align: center; line-height: 4em; text-decoration: none; text-transform: capitalize;}设置按钮悬停效果:.open-popup:hover { border-width: 2px;}至此,主界面完成,接下来制作弹窗。在 dom 中增加的 .popup 小节表示弹窗内容,其中的 <a> 是返回按钮,<p> 是具体内容,这里我们把内容简化为一些陆生动物的 unicode 字符,为了能够触发这个弹窗,设置 .popup 的 id 为 terrestrial,并在 .main 的 <a> 链接中指向它:<div class=“main”> <a href="#terrestrial" class=“open-popup”>terrestrial animals</a></div><section id=“terrestrial” class=“popup”> <a href="#" class=“back”>&lt; back</a> <p>????????????????????????????????????????</p></section>设置弹窗的尺寸,它将覆盖刚才的 .main 的内容:.popup { position: absolute; top: 0; width: 100%; height: inherit; display: flex; flex-direction: column; justify-content: start;}设置返回按钮的样式:.popup .back { font-size: 20px; font-family: sans-serif; text-align: center; height: 2em; line-height: 2em; background-color: #ddd; color: black; text-decoration: none;}.popup .back:visited { color: black;}.popup .back:hover { background-color: #eee;}设置内容的样式:.popup p { font-size: 100px; text-align: center; margin: 0.1em 0.05em;}设置弹窗内容默认是不显示的,只有点击主界面的链接时才显示:.popup { display: none;}.popup:target { display: flex;}至此,弹窗完成,但弹窗中的内容是重叠在主界面上面的,接下来制作从主界面到弹窗的动画效果。动画效果包含 3 个步骤:页面中间的一条直线从左端横穿到右端,页面中间大幕向上下两端拉开,最后内容淡入,下面的制作过程依次是第 3 个步骤、第 2 个步骤、第 1 个步骤。先让弹窗内容淡入:.popup > * { filter: opacity(0); animation: fade 0.5s ease-in forwards;}@keyframes fade{ to { filter: opacity(1); }}用伪元素 ::before 制作一个白色背景,从页面中间向上下两端展开:.popup::before { content: ‘’; position: absolute; box-sizing: border-box; width: 100%; height: 0; top: 50%; background-color: white; animation: open-animate 0.5s cubic-bezier(0.8, 0.2, 0, 1.2) forwards;}@keyframes open-animate { to { height: 100vh; top: 0; }}设置弹窗淡入动画的延时时长,形成先大幕拉开再显示内容的效果:.popup > * { animation-delay: 0.5s;}用伪元素 ::after 制作一条横线,从页面左端横穿到右端:.popup::after { content: ‘’; position: absolute; width: 0; height: 2px; background-color: white; top: calc((100% - 2px) / 2); left: 0; animation: line-animate 0.5s cubic-bezier(0.8, 0.2, 0, 1.2);}@keyframes line-animate { 50%, 100% { width: 100%; }}再设置弹窗淡入动画和大幕拉开动画的延时时长,让动画效果依次执行:.popup > * { animation-delay: 1s;}.popup::before { animation-delay: 0.5s;}至此,整个动画效果完成。在 dom 再中增加一组水生动物的内容,以及打开它的链接:<div class=“main”> <a href="#terrestrial" class=“open-popup”>terrestrial animals</a> <a href="#aquatic" class=“open-popup”>aquatic animals</a></div><section id=“terrestrial” class=“popup”> <a href="#" class=“back”>&lt; back</a> <p>????????????????????????????????????????</p></section><section id=“aquatic” class=“popup”> <a href="#" class=“back”>&lt; back</a> <p>????????????????????????????????????????</p></section>最后,设置一下主界面上按钮的间距:.open-popup { margin: 1em;}大功告成! ...

October 23, 2018 · 2 min · jiezi

‘纯css实现Material Design中的水滴动画按钮’的js体验优化

前言在上一篇,我们已经实现了用纯css实现水滴扩散动画,但是有一些瑕疵,文章结尾处也提到过,一是页面加载进来就会看到按钮上的水滴动画运动一次,二是点击的时候不能根据鼠标的位置来扩散,今天我们来解决这个问题。以下所有基础代码均来自上一篇css中只能做到固定的点扩散无法避免的js虽然我很想通过css来实现想要的效果,毕竟属于UI交互方面,尽量别扯上js,无奈后劲不足,很多功能确实无法实现,比如获取鼠标位置,这个css就真没辙了。思考了很久,还是只能通过js来获取位置坐标了,但是我们可以减少js的逻辑,我们只需要知道坐标即可,剩下的给css来做就好了。实现思路css新特性其实用的css很多新特性的话,很多以前只能通过js来实现的css也可以代替了。css原生变量var,大家平时应该都接触过了吧。可能平时由于兼容性的问题,用起来缩手缩脚,干脆为了兼容性就不用了其实只要不考虑IE的话兼容性还是可以的,就算要兼顾IE,可以保证按钮是完好的,只是没有动画效果不就可以了吗,这也是所谓的优雅降级吧var的用法很简单:root { –main-bg-color: red;}.container { width: 20px; height: 20px; background-color: var(–main-bg-color);/background-color:red/}有关var的详细用法,大家可以自行百度全能js我们用js只有一个目的,就是获取鼠标点击的位置很简单,事件对象event中有个offsetX和offsetY就是用来描述鼠标位置相对于父元素的位置其实这个属性早些年是IE私有的,谷歌和火狐看着好用,不知道从上面版本也都支持了,所以兼容性没太大问题~var x = event.offsetX;var y = event.offsetY;具体实现我们需要在点击的时候获取到左边,然后存在css变量中示例代码function ripple(ev){ var x = ev.offsetX; var y = ev.offsetY; this.style.setProperty(’–x’,x+‘px’); this.style.setProperty(’–y’,y+‘px’);}没错,就这么一丁点js相应的css部分我们要拿到我们保存的变量,来改变中心点的位置.btn>span:after{ content: ‘’; position: absolute; background: transparent; border-radius:50%; width: 100%; padding-top: 100%; margin-left: -50%; margin-top: -50%; left: var(–x,-100%); top: var(–y,-100%); }这里我们解决了两个问题,首次进来会触发一次:这里我们把left给了一个默认值-100%left: var(–x,-100%);也就是说,当前面的–x没有值或者非法的时候就会取后面一个值,-100%会让水滴动画的过程在视线之外触发,页面上根本看不见。跟随鼠标点击的位置扩散:现在已经获取到了鼠标的位置,所以就很容易实现了鼠标在哪点击就从哪里扩散的问题完整demohttps://codepen.io/xboxyan/pe…小节其实js实现是很简单的,css才是难点,css远比js灵活的多。比方说积木,积木的各种小零件是固定的,种类也有限,但是你可以组合出各种不同的玩具出来,可以称之为头脑创意吧,然而你组合出来一辆小汽车,却没法自动行驶,那么你就需要用上电机模组了,这是功能驱动。实际上在研发积木的过程中才是最耗费心思的地方,那些动力系统才是一层不变的。

October 22, 2018 · 1 min · jiezi

使用electron实现百度网盘悬浮窗口功能!

相关依赖里面使用了vuex vue vue-route storeJsstoreJs 用来持久化vuex状态展示介绍说明没有使用electron内置的-webkit-app-region: drag 因为使用他那个有很多问题比如事件无法使用 右键无法使用 以及不能使用手型等!安装安装的时候没有截图 所以就参考下我其他的文章吧storeJs 安装npm install storejs准备写代码配置路由文件export default new Router({ routes: [ {path: ‘/’, name: ‘home’, component: ()=> import(’@/view//home’)}, {path: ‘/suspension’, name: ‘suspension’, component: ()=> import(’@/view/components/suspension’)} ]})写悬浮窗页面页面路径 /src/renderer/view/components/suspension.vue<template> <div id=“suspension”> <div class=“logo”></div> <div class=“content_body”> <div class=“upload”>拖拽上传</div> </div> </div></template><script> export default { name: “suspension”, mounted() { let win = this.$electron.remote.getCurrentWindow(); let biasX = 0; let biasY = 0; let that = this; document.addEventListener(‘mousedown’, function (e) { switch (e.button) { case 0: biasX = e.x; biasY = e.y; document.addEventListener(‘mousemove’, moveEvent); break; case 2: that.$electron.ipcRenderer.send(‘createSuspensionMenu’); break; } }); document.addEventListener(‘mouseup’, function () { biasX = 0; biasY = 0; document.removeEventListener(‘mousemove’, moveEvent) }); function moveEvent(e) { win.setPosition(e.screenX - biasX, e.screenY - biasY) } } }</script><style> * { padding: 0; margin: 0; } .upload { height: 25px; line-height: 25px; font-size: 12px; text-align: center; color: #74A1FA; } .logo { width: 40px; background: #5B9BFE url("../../assets/img/logo@2x.png") no-repeat 2px 3px; background-size: 80%; } .content_body { background-color: #EEF4FE; width: 100%; } #suspension { -webkit-user-select: none; cursor: pointer; overflow: hidden; } #suspension { cursor: pointer !important; height: 25px; border-radius: 4px; display: flex; border: 1px solid #3388FE; }</style>主进程创建悬浮窗页面代码路径: /src/main/window.jsimport {BrowserWindow, ipcMain, screen, Menu, shell, app, webContents} from ’electron’var win = null;const window = BrowserWindow.fromWebContents(webContents.getFocusedWebContents());const winURL = process.env.NODE_ENV === ‘development’ ? http://localhost:9080/#/suspension : file://${__dirname}/index.html/#/suspension;ipcMain.on(‘showSuspensionWindow’, () => { if (win) { if (win.isVisible()) { createSuspensionWindow(); } else { win.showInactive(); } } else { createSuspensionWindow(); }});ipcMain.on(‘createSuspensionMenu’, (e) => { const rightM = Menu.buildFromTemplate([ {label: ‘开始全部任务’, enabled: false}, {label: ‘暂停全部任务’, enabled: false}, {label: ‘本次传输完自动关机’}, {type: ‘separator’}, { label: ‘隐藏悬浮窗’, click: () => { window.webContents.send(‘hideSuspension’, false); win.hide() } }, {type: ‘separator’}, { label: ‘加入qq群’, click: () => { shell.openExternal(’tencent://groupwpa/?subcmd=all&param=7B2267726F757055696E223A3831343237303636392C2274696D655374616D70223A313533393531303138387D0A’); } }, { label: ‘GitHub地址’, click: () => { shell.openExternal(‘https://github.com/lihaotian0607/auth’); } }, { label: ‘退出软件’, click: () => { app.quit(); } }, ]); rightM.popup({});});function createSuspensionWindow() { win = new BrowserWindow({ width: 107, //悬浮窗口的宽度 比实际DIV的宽度要多2px 因为有1px的边框 height: 27, //悬浮窗口的高度 比实际DIV的高度要多2px 因为有1px的边框 type: ’toolbar’, //创建的窗口类型为工具栏窗口 frame: false, //要创建无边框窗口 resizable: false, //禁止窗口大小缩放 show: false, //先不让窗口显示 webPreferences: { devTools: false //关闭调试工具 }, transparent: true, //设置透明 alwaysOnTop: true, //窗口是否总是显示在其他窗口之前 }); const size = screen.getPrimaryDisplay().workAreaSize; //获取显示器的宽高 const winSize = win.getSize(); //获取窗口宽高 //设置窗口的位置 注意x轴要桌面的宽度 - 窗口的宽度 win.setPosition(size.width - winSize[0], 100); win.loadURL(winURL); win.once(‘ready-to-show’, () => { win.show() }); win.on(‘close’, () => { win = null; })}ipcMain.on(‘hideSuspensionWindow’, () => { if (win) { win.hide(); }});store文件路径: /src/renderer/store/modules/suspension.jsimport storejs from ‘storejs’const state = { show: storejs.get(‘showSuspension’)};const actions = { showSuspension: function ({state, commit}) { let status = true; storejs.set(‘showSuspension’, status); state.show = status; }, hideSuspension: function ({state, commit}) { let status = false; storejs.set(‘showSuspension’, status); state.show = status; },};export default ({ state, actions});版权说明里面使用的百度的图标以及UI作为学习使用,请不要作为商业用途!遗留问题在软件关闭之后重启会导致悬浮窗口的位置重置 也曾尝试在主进程中使用store.js 但是不能用!如果想解决这个问题 可以在渲染进程中将拖动的最后坐标保存到storejs中在渲染进程给主进程发送异步消息的时候将坐标携带进去 也可以使用nedb在主进程中存储坐标!github地址使用electron制作百度网盘客户端: https://github.com/lihaotian0…使用electron制作百度网盘悬浮窗: https://github.com/lihaotian0…目前这个开源代码中没有悬浮窗 有时间了会加上去!!! ...

October 22, 2018 · 2 min · jiezi

前端每日实战:159# 视频演示如何用 CSS 和 Vanilla.js 创作一个展示苹果设备的交互动画

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/gBKWdW可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。第 1 部分:https://scrimba.com/p/pEgDAM/cazRgcL第 2 部分:https://scrimba.com/p/pEgDAM/ceDK7cB源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,包含 5 个子元素,分别代表 iphone, mini, ipad, macbook, imac 这 5 种设备:<div class=“container”> <div class=“device iphone”></div> <div class=“device mini”></div> <div class=“device ipad”></div> <div class=“device macbook”></div> <div class=“device imac”></div></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #aaa;}设置容器中子元素的布局方式:.container { position: relative; display: flex; flex-direction: column; align-items: center;}设置设备的共有属性,线性渐变图案将作为屏幕的背景:.device { box-sizing: border-box; position: relative; display: flex; justify-content: center; background: linear-gradient(120deg, #ddd 30%, #ccc 30%);}.device::before,.device::after { content: ‘’; position: absolute;}iphone, mini, ipad 的造型相似,都有顶部摄像头、传感器开口和底部按钮,所以这些共有属性可以一起设置,用 ::before 伪元素画出顶部细节,::after 伪元素画出底部按钮:.iphone::before,.mini::before,.ipad::before { width: 2px; height: 2px; border-style: solid; border-color: #a5adbe; border-width: 0 12px 0 2px;}.iphone::after,.mini::after,.ipad::after { width: 8px; height: 8px; background-color: white; border-radius: 50%;}接下来逐个画出设备。先画出 iphone 的轮廓:.iphone { width: 59px; height: 124px; border: #484f5e solid; border-width: 18px 4px; border-radius: 6px;}定位 iphone 的顶部和底部细节:.iphone::before { top: -10px;}.iphone::after { bottom: -13px;}类似地,画出 mini:.mini { width: 93px; height: 138px; border: #484f5e solid; border-width: 14px 5px; border-radius: 10px;}.mini::before { top: -8px;}.mini::after { bottom: -11px;}再画出 ipad:.ipad { width: 134px; height: 176px; border: #484f5e solid; border-width: 18px 13px; border-radius: 12px;}.ipad::before { top: -10px;}.ipad::after { bottom: -13px;}接下来画 macbook,先画屏幕:.macbook { width: 234px; height: 155px; border: 8px solid #484f5e; border-radius: 7px 7px 0 0;}用 ::before 伪元素画出摄像头:.macbook::before { width: 294px; height: 14px; background-color: #e8ebf0; top: calc(100% + 8px); border-radius: 0 0 14px 14px;}用 ::after 伪元素画出主机:.macbook::after { width: 3px; height: 3px; background-color: #a5adbe; top: -6px; border-radius: 50%;}接下来画 imac,先画屏幕,屏幕的左、上、右的黑色边框没有用 border 属性画,是因为 border 会在端点处遗留一个斜角,所以改用 box-shadow 实现:.imac { width: 360px; height: 215px; border-radius: 10px; box-shadow: inset 0 14px #484f5e, inset 14px 0 #484f5e, inset -14px 0 #484f5e; border-bottom: 33px solid #e8ebf1; transform: translateY(14px);}用 ::before 伪元素画出梯形的底座:.imac::before { width: 90px; height: 0; top: calc(100% + 33px); border: solid transparent; border-bottom-color: #e2e4e8; border-width: 0 10px 47px 10px;}用 ::after 伪元素画出顶部的摄像头和屏幕底部的按钮,注意按钮是用 box-shadow 实现的:.imac::after { width: 4px; height: 4px; background-color: #a5adbe; top: 5px; border-radius: 50%; box-shadow: 0 191px 0 4px #464e5d;}至此,设备全部绘制完成。删除除 iphone 之外的其他设备的 dom 元素,只保留 1 个 dom 元素,后面的动画效果都在这个 dom 元素上变化:<div class=“container”> <div class=“device iphone”></div> <!– <div class=“device mini”></div> <div class=“device ipad”></div> <div class=“device macbook”></div> <div class=“device imac”></div> –> </div>设置容器尺寸,子元素垂直居中,设备的高度占容器高度的 75%:.container { width: 360px; height: 350px; justify-content: center;}.device { transform: translateY(-25%);}在 dom 中增加 2 个按钮元素,分别用 .left 和 .right 表示:<div class=“container”> <div class=“device iphone”></div> <div class=“buttons”> <span class=“left”></span> <span class=“right”></span> </div></div>定位按钮的位置:.buttons { position: absolute; width: inherit; font-size: 30px; height: 2em; bottom: 0; display: flex; justify-content: space-around;}.buttons > * { position: relative; width: 4em;}按钮为向左和向右的箭头:.buttons > *::before { position: absolute;}.buttons .left::before { content: ‘←’; right: 0;}.buttons .right::before { content: ‘→’;}设置按钮样式为圆形:.buttons > *t::before { position: absolute; width: 2em; height: 2em; background-color: #484f5e; color: silver; text-align: center; line-height: 2em; border-radius: 1em; cursor: pointer;}增加鼠标悬停效果:.buttons > *::before { transition: 0.2s;}.buttons .left:hover::before { width: 4em; content: ‘⟵’;}.buttons .right:hover::before { width: 4em; content: ‘⟶’;}增加按钮点击效果:.buttons > *:active { transform: scale(0.9); filter: brightness(0.8);}至此,按钮制作完毕,接下来创建交互脚本。定义一个获取元素的函数 $:const $ = (className) => document.getElementsByClassName(className)[0]定义一个存放设备名称的数组:let devices = [‘iphone’, ‘mini’, ‘ipad’, ‘macbook’, ‘imac’]定义点击行为对数据的加工方法,当点击左侧按钮时,把数组最左边的 1 个元素移到最右边,相反地,当点击右侧按钮时,把数组最右边的 1 个元素移到最左边,这样就可以从 2 个方向循环遍历数组了:let loop = { ’left’: () => devices.unshift(devices.pop()), ‘right’: () => devices.push(devices.shift())}定义点击事件,根据数组的变化切换设备:Array.from($(‘buttons’).children).forEach(element => element.addEventListener(‘click’, function(e) { loope.target.className $(‘device’).className = ‘device ’ + devices[0] }))最后,设置设备切换的缓动效果:.device,.device::before,.device::after { transition: 0.4s cubic-bezier(0.5, 1.7, 0.5, 1.2);}大功告成! ...

October 21, 2018 · 3 min · jiezi

css3实现颤动的动画

需求页面要做一个活动入口,不能太显眼,但是又要用户能一眼就看出来。演示https://jsfiddle.net/vtsxc18q/实现 (部分动画代码)@keyframes chanDong { 5% { -webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg); transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg); } 6%, 8%, 10%, 12% { -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 10deg); transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 10deg); } 7%, 9%, 11% { -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -10deg); transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -10deg); } 13% { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } }Github 代码https://github.com/lmxdawn/te…另附一个 vue 搭建的后台管理另附一个 vue 搭建的后台管理 https://segmentfault.com/a/11… ...

October 19, 2018 · 1 min · jiezi

前端每日实战:158# 视频演示如何用纯 CSS 创作一个雨伞 toggle 控件

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/pxLbjv可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cMV8euJ源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器 .umbralla 中包含 2 个元素,.canopy 代表伞盖,.shaft 伞柄:<figure class=“umbralla”> <div class=“canopy”></div> <div class=“shaft”></div></figure>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background: linear-gradient(skyblue, lightblue);}设置伪元素的共有属性:.umbrella *::before,.umbrella *::after { content: ‘’; position: absolute;}先画出雨伞打开的样子。设置容器尺寸,其中 font-size 的属性值后面还要用到,所以定义了一个变量::root { –font-size: 10px;}.umbrella { position: relative; width: 25em; height: 26em; font-size: var(–font-size);}定义伞盖的尺寸:.umbrella .canopy { position: absolute; width: inherit; height: 5.5em; top: 2.5em;}用 ::before 伪元素画出伞盖的上半部分,方法先画一个半圆,然后在垂直方向上压缩它:.umbrella .canopy::before { width: inherit; height: 12.5em; background: rgb(100, 100, 100); border-radius: 12.5em 12.5em 0 0; transform: scaleY(0.4); top: -4em;}用 ::after 伪元素画出伞盖的下半部分:.umbrella .canopy::after { width: inherit; height: 1.5em; background-color: #333; top: 4em; border-radius: 50%;}画出伞柄的长杆:.umbrella .shaft { position: absolute; width: 0.8em; height: 18em; background-color: rgba(100, 100, 100, 0.7); top: 5.5em; left: calc((100% - 0.8em) / 2);}用伪元素画出伞杆顶部露出伞盖的尖头,方法和画伞盖上半部分类似,先画出半圆,然后在水平方向上压缩它:.umbrella .shaft::before { width: 6em; height: 3em; background-color: rgba(100, 100, 100, 0.7); left: calc((100% - 6em) / 2); top: -5.5em; border-radius: 6em 6em 0 0; transform: scaleX(0.1);}画出雨伞的钩形把手:.umbrella .shaft::after { box-sizing: border-box; width: 4em; height: 2.5em; border: 1em solid #333; top: 100%; left: calc(50% - 4em + 1em / 2); border-radius: 0 0 2.5em 2.5em; border-top: none;}至此,完成了雨伞打开的样子,接下来通过变形画出雨伞合上时的样子。先把伞盖的合上,方法是在水平方向上压缩,在垂直方向上拉伸:.umbrella .canopy { transform-origin: top; transform: scale(0.08, 4);}隐藏伞盖的下半部分:.umbrella .canopy::after { transform: scaleY(0);}让伞倾斜,因为竖着的伞有点呆板,所以增加一点变化:.umbrella { transform: rotate(-30deg);}至此,雨伞合上时的样子也完成了,接下来要把它变为 toggle 控件了。在 dom 中增加一个 checkbox 控件:<input type=“checkbox” class=“toggle”><figure class=“umbrella”> <!– 略 –></figure>设置控件与雨伞一样大,并置于雨伞图层的上层:.toggle { position: absolute; filter: opacity(0); width: 25em; height: 26em; font-size: var(–font-size); cursor: pointer; z-index: 2;}checkbox 控件的未选中状态对应雨伞合上时的样子,也就是目前雨伞的样子,所以只要指定控件被选中状态对应的雨伞打开时的样子就可以了。因为合上雨伞是对几个元素进行变形得到的,所以转换到雨伞打开状态就是取消变形。先让伞正过来:.toggle:checked ~ .umbrella { transform: rotate(0deg);}然后把伞盖打开:.toggle:checked ~ .umbrella .canopy { transform: scale(1, 1);}再显示出伞盖的下半部分:.toggle:checked ~ .umbrella .canopy::after { transform: scaleY(1);}最后,设置以上几个元素的缓动效果:.umbrella,.umbrella .canopy,.umbrella .canopy::after { transition: 0.3s cubic-bezier(0.5, -0.25, 0.5, 1.25);}大功告成! ...

October 18, 2018 · 2 min · jiezi

深入理解BFC

一、什么是BFCFormatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。Block formatting context直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。通俗地讲,BFC是一个容器,用于管理块级元素。二、如何创建BFCfloat为 left|rightoverflow为 hidden|auto|scrolldisplay为 table-cell|table-caption|inline-block|inline-flex|flexposition为 absolute|fixed根元素三、BFC布局规则:内部的Box会在垂直方向,一个接一个地放置(即块级元素独占一行)。BFC的区域不会与float box重叠(利用这点可以实现自适应两栏布局)。内部的Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠(margin重叠三个条件:同属于一个BFC;相邻;块级元素)。计算BFC的高度时,浮动元素也参与计算。(清除浮动 haslayout)BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。四、 BFC有哪些特性特性1:BFC会阻止垂直外边距折叠按照BFC的定义,只有同属于一个BFC时,两个元素才有可能发生垂直margin的重叠,这个包括相邻元素或者嵌套元素,只要他们之间没有阻挡(比如边框、非空内容、padding等)就会发生margin重叠。①相邻兄弟元素margin重叠问题<style>p{ color: #fff; background: #888; width: 200px; line-height: 100px; text-align:center; margin: 100px; }</style><body> <p>ABC</p> <p>abc</p></body>上面例中两个P元素之间距离本该为200px,然而实际上只有100px,发生了margin重叠。遇到这种情形,我们如何处理?只需要在p外面包裹一层容器,并触发该容器生成一个BFC。那么两个P便不属于同一个BFC,就不会发生margin重叠了。<style>p{ color: #fff; background: #888; width: 200px; line-height: 100px; text-align:center; margin: 100px; }.wrap{ overflow:hidden;}</style><body> <p>ABC</p> <div class=“wrap”> <p>abc</p> </div></body>②父子元素margin重叠问题<style>.box{width:100px;height:100px;background:#ccc;}.wrap { background:yellow;}.wrap h1{ background:pink; margin:40px;}</style><body><div class=“box”>box</div><div class=“wrap”> <h1>h1</h1></div></body>上图wrap元素与h1元素之间l理论上本该有个40px的上下margin值,然而实际上父子元素并没有存在margin值,与此同时,两个div元素的间距为40px。遇到这种情形,我们如何处理?处理方法其实有很多,在wrap元素中添加:overflow:hidden;或者overflow:auto;使其父元素形成一个BFC;也可以在wrap元素中添加border:1px solid;或是padding:1px;这些都可以有效解决父子元素margin重叠问题。特性2:BFC不会重叠浮动元素利用这个特性,我们可以创造自适应两栏布局。<style>.box1{ height: 100px; width: 100px; float: left; background: lightblue;}.box2{width: 200px; height: 200px; background: #eee;}</style><body><div class=“box1”>我是一个左浮动的元素</div><div class=“box2”>喂喂喂!大家不要生气嘛,生气会犯嗔戒的。悟空你也太调皮了,我跟你说过叫你不要乱扔东西,你怎么又……你看,我还没说完你就把棍子给扔掉了!月光宝盒是宝物,你把它扔掉会污染环境,要是砸到小朋友怎么办,就算砸不到小朋友,砸到花花草草也是不对的。</div></body>上图中,文字围绕着浮动元素排列,不过在这里,这显然不是我们想要的。此时我们可以为.box2元素的样式加上overflow:hidden;使其建立一个BFC,让其内容消除对外界浮动元素的影响。这个方法可以用来实现两列自适应布局,效果不错,此时左边的宽度固定,右边的内容自适应宽度。如果我们改变文字的大小或者左边浮动元素的大小,两栏布局的结构依然没有改变!特性3:BFC可以包含浮动—-清除浮动我们都知道浮动会脱离文档流,接下来我们看看下面的例子:<style>.box1{ width:100px; height:100px; float:left; border: 1px solid #000;}.box2{ width:100px; height:100px; float:left; border: 1px solid #000;}.box{ background:yellow}</style><body><div class=“box”> <div class=“box1”></div> <div class=“box2”></div></div> </body>由于容器内两个div元素浮动,脱离了文档流,父容器内容宽度为零(即发生高度塌陷),未能将子元素包裹住。解决这个问题,只需要把把父元素变成一个BFC就行了。常用的办法是给父元素设置overflow:hidden。本文于2018.10.14重新修改,希望文章对你有些许帮助,欢迎在我的GitHub博客点赞和关注,感激不尽!参考文章【CSS】深入理解BFC原理及应用10 分钟理解 BFC 原理 ...

October 18, 2018 · 1 min · jiezi

前端每日实战:157# 视频演示如何用纯 CSS 创作一个棋盘错觉动画(实际上每一行都是平行的)

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/VEyoGj可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cppKmsd源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 10 个子元素,每个子元素表示一行:<div class=“container”> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center;}定义容器尺寸,用 vmin 单位,并让子元素竖向排列:.container { width: 100vmin; height: 100vmin; display: flex; flex-direction: column;}设置子元素的背景图案为间隔的黑白色块,顶部有一条细线:.container span { width: inherit; height: 10vmin; background: linear-gradient( gray, gray 0.5vmin, transparent 0.5vmin, transparent ), repeating-linear-gradient( to right, black, black 10vmin, transparent 10vmin, transparent 20vmin )}在容器底部补一条细线:.container { border-bottom: 0.5vmin solid gray;}增加动画效果,让奇数行的背景向右移动半个色块的位置,移动之后看起来好像奇数行右宽左窄,偶数行左宽右窄,这是一种错觉:.container span:nth-child(odd) { animation: move 5s linear infinite;}@keyframes move { 0%, 55%, 100% { background-position: 0 0; } 5%, 50% { background-position: 5vmin 0; }}让偶数行的背景也移动起来,产生相反方向的错觉:.container span:nth-child(even) { animation: move 5s linear infinite reverse;}大功告成! ...

October 17, 2018 · 1 min · jiezi

如何居中一个元素(终结版)

前言本文主要介绍水平居中,垂直居中,还有水平垂直居中各种办法,思维导图如下:一、水平居中1.行内元素水平居中利用 text-align: center 可以实现在块级元素内部的行内元素水平居中。此方法对inline、inline-block、inline-table和inline-flex元素水平居中都有效。 .parent{//在父容器设置 text-align:center; }此外,如果块级元素内部包着也是一个块级元素,我们可以先将其由块级元素改变为行内块元素,再通过设置行内块元素居中以达到水平居中。<div class=“parent”> <div class=“child”>Demo</div></div><style> .parent{ text-align:center; } .child { display: inline-block; }</style>2.块级元素的水平居中这种情形可以有多种实现方式,下面我们详细介绍:①将该块级元素左右外边距margin-left和margin-right设置为auto.child{ width: 100px;//确保该块级元素定宽 margin:0 auto;}②使用table+margin先将子元素设置为块级表格来显示(类似),再将其设置水平居中display:table在表现上类似block元素,但是宽度为内容宽。<div class=“parent”> <div class=“child”>Demo</div></div><style> .child { display: table; margin: 0 auto; }</style>③使用absolute+transform先将父元素设置为相对定位,再将子元素设置为绝对定位,向右移动子元素,移动距离为父容器的一半,最后通过向左移动子元素的一半宽度以达到水平居中。<div class=“parent”> <div class=“child”>Demo</div></div><style> .child { position:absolute; left:50%; transform:translateX(-50%); } .parent { position:relative; }</style>不过transform属于css3内容,兼容性存在一定问题,高版本浏览器需要添加一些前缀。④使用flex+justify-content通过CSS3中的布局利器flex中的justify-content属性来达到水平居中。<div class=“parent”> <div class=“child”>Demo</div></div><style> .parent { display: flex; justify-content:center; }</style>⑤使用flex+margin通过flex将父容器设置为为Flex布局,再设置子元素居中。<div class=“parent”> <div class=“child”>Demo</div></div><style> .parent { display: flex; } .child { margin:0 auto; }</style>3.多块级元素水平居中①利用flex布局利用弹性布局(flex),实现水平居中,其中justify-content 用于设置弹性盒子元素在主轴(默认横轴)方向上的对齐方式,本例中设置子元素水平居中显示。 #container { display: flex; justify-content: center;}源代码演示②利用inline-block将要水平排列的块状元素设为display:inline-block,然后在父级元素上设置text-align:center,达到与上面的行内元素的水平居中一样的效果。.container {text-align: center;}.inline-block {display: inline-block;}源代码演示4.浮动元素水平居中对于定宽的浮动元素,通过子元素设置relative + 负margin对于不定宽的浮动元素,父子容器都用相对定位通用方法(不管是定宽还是不定宽):flex布局①定宽的非浮动元素通过子元素设置relative + 负margin,原理见下图:注意:样式设置在浮动元素本身.child { position:relative; left:50%; margin-left:-250px;}<div class=“parent”> <span class=“child” style=“float: left;width: 500px;">我是要居中的浮动元素</span></div>②不定宽的浮动元素通过父子容器都相对定位,偏移位移见下图:注意:要清除浮动,给外部元素加上float。这里的父元素就是外部元素<div class=“box”> <p>我是浮动的</p> <p>我也是居中的</p></div>.box{ float:left; position:relative; left:50%;}p{ float:left; position:relative; right:50%;}③通用办法flex布局(不管是定宽还是不定宽)利用弹性布局(flex)的justify-content属性,实现水平居中。.parent { display:flex; justify-content:center;}.chlid{ float: left; width: 200px;//有无宽度不影响居中}<div class=“parent”> <span class=“chlid”>我是要居中的浮动元素</span></div>5.绝对定位元素水平居中这种方式非常独特,通过子元素绝对定位,外加margin: 0 auto来实现。<div class=“parent”> <div class=“child”>让绝对定位的元素水平居中对齐。</div></div> .parent{ position:relative; } .child{ position: absolute; /绝对定位/ width: 200px; height:100px; background: yellow; margin: 0 auto; /水平居中/ left: 0; /此处不能省略,且为0/ right: 0;/此处不能省略,且为0/ }二、垂直居中1.单行内联元素垂直居中<div id=“box”> <span>单行内联元素垂直居中。</span>。</div><style> #box { height: 120px; line-height: 120px; border: 2px dashed #f69c55; }</style>2.多行内联元素垂直居中①利用flex布局(flex)利用flex布局实现垂直居中,其中flex-direction: column定义主轴方向为纵向。这种方式在较老的浏览器存在兼容性问题。<div class=“parent”> <p>Dance like nobody is watching, code like everybody is. Dance like nobody is watching, code like everybody is. Dance like nobody is watching, code like everybody is.</p></div><style> .parent { height: 140px; display: flex; flex-direction: column; justify-content: center; border: 2px dashed #f69c55; }</style>②利用表布局(table)利用表布局的vertical-align: middle可以实现子元素的垂直居中<div class=“parent”> <p class=“child”>The more technology you learn, the more you realize how little you know. The more technology you learn, the more you realize how little you know. The more technology you learn, the more you realize how little you know.</p></div> <style> .parent { display: table; height: 140px; border: 2px dashed #f69c55; } .child { display: table-cell; vertical-align: middle; }</style>3 块级元素垂直居中①使用absolute+负margin(已知高度宽度)通过绝对定位元素距离顶部50%,并设置margin-top向上偏移元素高度的一半,就可以实现了。<div class=“parent”> <div class=“child”>固定高度的块级元素垂直居中。</div></div>.parent {position: relative;}.child {position: absolute;top: 50%;height: 100px;margin-top: -50px;}②使用absolute+transform当垂直居中的元素的高度和宽度未知时,可以借助CSS3中的transform属性向Y轴反向偏移50%的方法实现垂直居中。但是部分浏览器存在兼容性的问题。<div class=“parent”> <div class=“child”>未知高度的块级元素垂直居中。</div></div>.parent {position: relative;}.child {position: absolute;top: 50%;transform: translateY(-50%);}③使用flex+align-items通过设置flex布局中的属性align-items,使子元素垂直居中。<div class=“parent”> <div class=“child”>未知高度的块级元素垂直居中。</div></div>.parent { display:flex; align-items:center;}④使用table-cell+vertical-align通过将父元素转化为一个表格单元格显示(类似 <td> 和 <th>),再通过设置 vertical-align属性,使表格单元格内容垂直居中。<div class=“parent”> <div class=“child”>Demo</div></div><style> .parent { display: table-cell; vertical-align: middle; }</style>三、水平垂直居中这种情形也是有多种实现方式,接下去我们娓娓道来:方法1:绝对定位与负边距实现(已知高度宽度)这种方式需要知道被垂直居中元素的高和宽,才能计算出margin值,兼容所有浏览器。// css部分 #container { position: relative; } #center { position: absolute; top: 50%; left: 50%; margin: -50px 0 0 -50px; }// html部分(这部分不做变化,下面例子直接共用)<body> <div id=‘container’> <div id=‘center’ style=“width: 100px;height: 100px;background-color: #666”>center</div> </div></body>方法2:绝对定位与margin:auto(已知高度宽度)这种方式无需知道被垂直居中元素的高和宽,但不能兼容低版本的IE浏览器。 #container { position: relative; height:100px;//必须有个高度 } #center { position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto;//注意此处的写法 }方法3:绝对定位+CSS3(未知元素的高宽)利用Css3的transform,可以轻松的在未知元素的高宽的情况下实现元素的垂直居中。CSS3的transform固然好用,但在项目的实际运用中必须考虑兼容问题,大量的hack代码可能会导致得不偿失。 #container { position: relative; } #center { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }方法4:flex布局利用flex布局,其中justify-content 用于设置或检索弹性盒子元素在主轴(横轴)方向上的对齐方式;而align-items属性定义flex子项在flex容器的当前行的侧轴(纵轴)方向上的对齐方式。不能兼容低版本的IE浏览器。 #container {//直接在父容器设置即可 height: 100vh;//必须有高度 display: flex; justify-content: center; align-items: center; }方法5:flex/grid与margin:auto(最简单写法)容器元素设为 flex 布局或是grid布局,子元素只要写 margin: auto 即可,不能兼容低版本的IE浏览器。 #container { height: 100vh;//必须有高度 display: grid; } #center { margin: auto; }如果觉得文章对你有些许帮助,欢迎在我的GitHub博客点赞和关注,感激不尽!后记写博客是件挺费精力的事,特别是你有想写出一篇好博客的初衷,本文前后花了不止五六个小时,但我却常常乐此不疲!一方面是看了很多博客,自己不手动敲一遍整理一遍,就感觉没掌握一样;另一方面,分享学习心得是件很快乐的事,愿与诸君共同成长进步!如果觉得本文还不错,记得点赞关注喔!因为往往是普通人才最需要别人的鼓励和支持!参考文章【基础】这15种CSS居中的方式,你都用过哪几种?最全面的水平垂直居中方案与flexbox布局CSS3 Flexbox轻巧实现元素的水平居中和垂直居中如何居中一个元素(正常、绝对定位、浮动元素)CSS布局解决方案(终结版)水平居中、垂直居中、水平垂直居中、浮动居中、绝对定位居中…….帮你搞定 ...

October 14, 2018 · 2 min · jiezi

前端每日实战:155# 视频演示如何用纯 CSS 创作一只热气球

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/KGveaN可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cgdaPsr源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中有 2 个子元素,.envelope 代表伞盖,.basket 代表吊篮:<figure class=“balloon”> <div class=“envelope”> <span></span> <span></span> </div> <div class=“basket”> <span></span> <span></span> <span></span> <span></span> </div></figure>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background: linear-gradient(deepskyblue, skyblue, lightblue 20%);}定义容器的尺寸,子元素 .envelope 和 .basket 纵向居中布局:.balloon { width: 12em; height: 19em; font-size: 16px; display: flex; flex-direction: column; align-items: center;}先画伞盖。定义伞盖的尺寸:.envelope { position: relative; width: inherit; height: 16em;}伞盖的形状是上端为球形,下端为圆锥形,在二维平面中,圆锥在平面的投影为等腰三角形,所以我们先在上部画一个圆,再在下部画一个三角形。先画上部的圆:.envelope span { position: absolute; width: inherit; height: 12em; border-radius: 50%; color: orange; background-color: currentColor;}再用伪元素画出下部的等腰三角形:.envelope span::before { content: ‘’; position: absolute; width: 0; height: 0; border-width: 10em 5.5em 0 5.5em; border-style: solid; border-color: currentColor transparent transparent transparent; left: calc(50% - 5.5em); top: 8.45em;}.envelope 下共有 2 个 <span> 元素,让第 2 个 <span> 变形、变色,使伞盖形成竖条纹的花纹:.envelope span:nth-child(2) { transform: scaleX(0.4); filter: brightness(0.85) contrast(1.4);}隐藏 .envelope 容器外的部分,削掉三角形最下面的尖角:.envelope { overflow: hidden;}至此,伞盖完成,接下来画吊篮。定义吊篮的尺寸:.basket { position: relative; width: 2em; height: 3em;}用 ::before 伪元素画出篮子:.basket::before { content: ‘’; position: absolute; width: inherit; height: 1.6em; background-color: peru; bottom: 0; border-radius: 0 0 0.5em 0.5em;}用 ::after 伪元素画出篮子的顶边:.basket::after { content: ‘’; position: absolute; width: 105%; height: 0.3em; background-color: saddlebrown; left: calc((100% - 105%) / 2); top: 1.3em; border-radius: 0.3em;}.basket 下共有 4 个 <span> 元素,代表 4 根缆绳,设置它们的样式为竖细线:.basket span { position: absolute; width: 0.1em; height: 1.5em; background-color: burlywood;}定位缆绳,并倾斜不同的角度:.basket span { left: calc((var(–n) - 1) * 0.6em); transform-origin: bottom; transform: rotate(calc(var(–r) * 7deg));}.basket span:nth-child(1) { –n: 1; –r: -2; }.basket span:nth-child(2) { –n: 2; –r: -1; }.basket span:nth-child(3) { –n: 3; –r: 1; }.basket span:nth-child(4) { –n: 4; –r: 2; }最后,增加热气球微微浮动的动画效果:.balloon { animation: drift 2s infinite alternate;}@keyframes drift { to { transform: translateY(-5%); }}大功告成! ...

October 13, 2018 · 2 min · jiezi

HTML5中dialog元素尝鲜

对话框(别称模态框,浮层)是web项目中用于用户交互的重要部分,我们最常见的就是js中 alert(),confirm(),但是这个对话框的不美观,也不能自定义样式,所以在开发的过程中,一般根据自己自己的需求造轮子或者使用第三方的。对话框的组成常见的弹出框形式:位置:屏幕的左上角,右上角,左下角,右下角,垂直居中等大小:定宽定高,定宽不定高,不定宽不定高等开发中的对话框形式就是位置和大小随机组合的一种情况。但是有一种情况(不定宽高的垂直居中)不易实现(可以使用display:table或css3的translate或flex实现),具体可参考水平垂直居中布局上面的对话框包含内容的容器,还有一个是对话框下面的遮罩层(mask),遮罩层是用户触发弹出框后,形成的一个对话框与页面主体的分割图层,它的存在可以给用户一个更明显的视觉差效果,同时也起到避免用户触发对话框后的其他不必要的页面主体操作,从而产生更有的用户体验。存在问题虽然,有很多对话框的轮子供我们选择,但是我们面临着各种各样的问题。到底选择哪一种对话框(对于有选择综合症的人来说一个头疼的问题)可用性(api的简单与否,是否依赖了其他第三方的库)可扩展性浏览器的兼容性支持那么,有没有一个简单的方法来做做一个对话框呢?当然有,我们可以使用HTML5的 dialog 元素。HTML5(dialog)<dialog open> <h2> Hello world.</h2></dialog>很简单,我们使用上面的代码就可以做一个弹出内容为‘Hello world.’ 的对话框。控制对话框的显示/隐藏也很容易,添加 open 属性表示显示,去除为隐藏。当然,我们也可以通过DOM接口来控制 dialog 的显隐(show(), close())对话框下面的遮罩层,我们可以使用 ::backgrop 伪元素,而它的激活,我们需要使用 showModal() 这个DOM的API,::backgrop 的特性是它的位置在dialog之下,在任何 z-index 之上。使用 showModal() 不仅可以让遮罩层显示,dialog容器也显示,所以用到 ::backdrop 的时候,可以用 showModal() 代替 show() 这个API;如果按键盘 ESC 键将关闭弹出层,当然你一可以使用 close() 这个DOM API。我们可以设置 ::backdrop 这个图层为半透明图层,代码如下:dialog::backdrop { background-color: rgba(0, 0, 0, 0.75);}除了我们常见的提示信息的弹出层外,还有一类比较使用的是带表单的弹出层。带表单的弹出层我们可以使用HTML5的dialog元素结合form元素来做这些弹出层吗?答:可以我们怎么做才能让form元素和dialog元素紧密的结合起来呢?答:我们只需要在dialog元素中添加 method=“dialog” 这个属性即可,这样就可以将button元素的属性 value 的值传递给dialog元素。<dialog> <form method=“dialog”> <p>确定 or 取消</p> <button type=“submit” value=“yes”>确定</button> <button type=“submit” value=“no”>取消</button> </form></dialog><script> var dialog = document.querySelector(‘dialog’) dialog.showModal() dialog.addEventListener(‘close’, function(event) { console.log(dialog.returnValue) })</script>demo浏览器兼容性虽然,这是一个比较好用的HTML5,但是还存在兼容性问题,chrome和opera支持的比较好,Firefox中是实验特性,但是IE,Edge, safari支持的不好,ios不支持,Android也支持的不够好,只有Android6以后支持。具体可参考caniuse那么,能不能让旧版本的浏览器支持HTML5的dialog呢?首先,我们想到的是有没有一个支持dialog的polyfill,就像支持es6新特性的babel-polyfill一样,确实有这样一个开源项目a11y-dialog,它分别提供了vue和react的不同版本。更多系列文章请关注我的github ...

October 13, 2018 · 1 min · jiezi

前端每日实战:153# 视频演示如何用 CSS 和 VanillaJS 创作一组 tooltip 提示框

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/rqyoYY可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/c6p2Es2源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含一个名为 .emoji 的子容器,代表一个头像,它的子元素 eye left、eye right、mouth 分别代表左眼、右眼和嘴巴:<section class=“container”> <div class=“emoji”> <span class=“eye left”></span> <span class=“eye right”></span> <span class=“mouth”></span> </div></section>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: lightyellow;}定义容器尺寸和子元素对齐方式:.container { position: relative; width: 20em; height: 20em; font-size: 10px; display: flex; align-items: center; justify-content: center;}定义头像的轮廓:.emoji { position: relative; box-sizing: border-box; width: 10em; height: 10em; background-color: pink; border-radius: 50% 50% 75% 50%;}定义头像眼睛的轮廓:.emoji .eye { position: absolute; box-sizing: border-box; width: 3em; height: 3em; border: 0.1em solid gray; border-radius: 50%; top: 3em;}.emoji .eye.left { left: 1em;}.emoji .eye.right { right: 1em;}画出眼珠:.emoji .eye.left::before,.emoji .eye.right::before { content: ‘’; position: absolute; width: 1em; height: 1em; background-color: #222; border-radius: 50%; top: 1em; left: calc((100% - 1em) / 2);}画出微笑的嘴:.emoji .mouth { position: absolute; width: 2em; height: 2em; border: 0.1em solid; bottom: 1em; left: 40%; border-radius: 50%; border-color: transparent gray gray transparent; transform: rotate(20deg);}接下来制作眼珠转向 4 个方向的效果。用 2 个变量分别表示眼珠的定位位置:.emoji .eye { –top: 1em; –left: calc((100% - 1em) / 2);}.emoji .eye.left::before,.emoji .eye.right::before { top: var(–top); left: var(–left);}设置眼珠在 4 个方向的定位位置:.emoji.top .eye { –top: 0;}.emoji.bottom .eye { –top: 1.8em;}.emoji.left .eye { –left: 0;}.emoji.right .eye { –left: 1.8em;}此时,如果为 dom 元素 .emoji 增加 top、bottom、left、right 4 个样式中的任何一个样式,眼珠就会转向特定的方向。在 dom 中增加 4 个元素,每个元素的内容是一个 @ 字符:<section class=“container”> <div class=“emoji”> <!– 略 –> </div> <span class=“tip top”>@</span> <span class=“tip left”>@</span> <span class=“tip right”>@</span> <span class=“tip bottom”>@</span></section>把 4 个元素布局在头像周围:.tip { position: absolute; cursor: pointer; font-size: 4.5em; color: silver; font-family: sans-serif; font-weight: 100;}.tip.top { top: -15%;}.tip.bottom { bottom: -15%;}.tip.left { left: -15%;}.tip.right { right: -15%;}写一段脚本,增加一点交互效果。当鼠标悬停在 4 个方向的 @ 上时,使眼珠朝相应的方向转去。这里的 DIRECTION 常量存储了 4 个方向,EVENTS 常量存储了 2 个鼠标事件,$ 常量包装了根据类名获取 dom 元素的操作:const DIRECTIONS = [’top’, ‘bottom’, ’left’, ‘right’]const EVENTS = [‘mouseover’, ‘mouseout’]const $ = (className) => document.getElementsByClassName(className)[0]DIRECTIONS.forEach(direction => EVENTS.forEach((e) => $(tip ${direction}).addEventListener(e, () => $(’emoji’).classList.toggle(direction) ) ))为眼珠设置缓动时间,使动画平滑:.emoji .eye.left::before,.emoji .eye.right::before { transition: 0.3s;}接下来制作 tooltip 提示框。为 4 个 @ 符号的 dom 增加 data-tip 属性,其内容就是 tooltip 信息:<section class=“container”> <div class=“emoji”> <!– 略 –> </div> <span class=“tip top” data-tip=“look up”>@</span> <span class=“tip bottom” data-tip=“look down”>@</span> <span class=“tip left” data-tip=“look to the left”>@</span> <span class=“tip right” data-tip=“look to the right”>@</span></section>用 ::before 伪元素展示提示信息,样式为黑底白字:.tip::before { content: attr(data-tip); position: absolute; font-size: 0.3em; font-family: sans-serif; width: 10em; text-align: center; background-color: #222; color: white; padding: 0.5em; border-radius: 0.2em; box-shadow: 0 0.1em 0.3em rgba(0, 0, 0, 0.3);}把顶部的提示框定位到顶部 @ 符号的上方正中:.tip.top::before { top: 0; left: 50%; transform: translate(-50%, calc(-100% - 0.6em));}类似地,把其他 3 个提示框也定位到 @ 符号的旁边:.tip.bottom::before { bottom: 0; left: 50%; transform: translate(-50%, calc(100% + 0.6em));}.tip.left::before { left: 0; top: 50%; transform: translate(calc(-100% - 0.6em), -50%);}.tip.right::before { right: 0; top: 50%; transform: translate(calc(100% + 0.6em), -50%);}用 ::after 伪元素在顶部提示框下面画出一个倒三角形:.tip::after { content: ‘’; position: absolute; font-size: 0.3em; width: 0; height: 0; color: #222; border: 0.6em solid transparent;}.tip.top::after { border-bottom-width: 0; border-top-color: currentColor; top: -0.6em; left: 50%; transform: translate(-50%, 0);}类似地,在其他 3 个提示框旁边画出三角形:.tip.bottom::after { border-top-width: 0; border-bottom-color: currentColor; bottom: -0.6em; left: 50%; transform: translate(-50%, 0);}.tip.left::after { border-right-width: 0; border-left-color: currentColor; left: -0.6em; top: 50%; transform: translate(0, -50%);}.tip.right::after { border-left-width: 0; border-right-color: currentColor; right: -0.6em; top: 50%; transform: translate(0, -50%);}最后,隐藏提示框,使提示框只在鼠标悬停时出现:.tip::before,.tip::after { visibility: hidden; filter: opacity(0); transition: 0.3s;}.tip:hover::before,.tip:hover::after { visibility: visible; filter: opacity(1);}大功告成! ...

October 12, 2018 · 3 min · jiezi

css实现波浪线及立方体

最近的项目有做到要画出波浪线效果,这里是利用linear-gradient来实现,也就是画圆,然后利用底色来遮住部分圆;利用css3属性perspective加旋转实现立方体1.css实现波浪线html<div class=“card-list”> <div class=“wave-container”> <div class=“wave”></div> <!– 实现波浪线的div –> <div class=“wave-left-decorate”></div> <div class=“wave-right-decorate”></div> </div></div>css.card-list{ display: flex; padding: 20px; width: 100%;}.wave-container{ position: relative; margin-right: 28px; width: 20%;}.wave{ width: 100%; height: 90px; background: linear-gradient(to right, rgb(85, 181, 255), rgb(207, 224, 232));}/* 波浪线 /.wave-left-decorate{ position: absolute; top: -4px; width: 90px; height: 8px; transform-origin: center left; transform: rotate(90deg); background: radial-gradient(circle, #fff 2px, #fff, transparent 3px, transparent 4px, transparent 4px, transparent); background-size: 8px 8px;}效果图2.实现立方体html文件<div class=“content”> <div class=“leftContent”> <div class=“leftContentItem”> <div class=“itemImg”> <img class=“leftContentImg” src=“images/rabbit.jpg” alt=""/> <img class=“leftContentImg” src=“images/rabbit.jpg” alt=""/> <img class=“leftContentImg” src=“images/rabbit.jpg” alt=""/> <img class=“leftContentImg” src=“images/rabbit.jpg” alt=""/> <img class=“leftContentImg” src=“images/rabbit.jpg” alt=""/> <img class=“leftContentImg” src=“images/rabbit.jpg” alt=""/> </div> </div> </div></div>css文件.content{ position: relative; display: flex; margin: 0 auto; padding-top: 50px; width: 1200px; height: 380px; background: url(../images/bg2.jpg) no-repeat; background-size: 1200px 100%;}.content .leftContent{ margin-right: 25px; padding-left: 45px; padding-bottom: 30px; box-sizing: border-box;}/ 旋转的图片 /.content .leftContent .leftContentItem{ width: 350px; height: 350px; / 设置景深 / perspective: 1000px; / 设置背景颜色在中间为椭圆形 / /background: radial-gradient(ellipse at center, #430d6d 0%, #000 100%);/}.leftContent .leftContentItem .itemImg{ position: absolute; left: 20%; top: 20%; width: 200px; height: 200px; / 实现3D呈现 */ transform-style: preserve-3d; transform: rotateX(-20deg) rotateY(-20deg); -webkit-animation: 6s imgRotate linear infinite; -o-animation: 6s imgRotate linear infinite; animation: 6s imgRotate linear infinite;}.leftContent .leftContentItem .itemImg { position: absolute; width: 100%; height: 100%; box-shadow: 0 0 25px rgba(0, 128, 0, .4);}.leftContentItem .itemImg .leftContentImg{ position: absolute; width: 100%; height: 100%;}/ 分别对各个面进行旋转、平移操作 */.leftContentItem .itemImg .leftContentImg:nth-child(1){ transform: translateZ(100px);}.leftContentItem .itemImg .leftContentImg:nth-child(2){ transform: rotateX(180deg) translateZ(100px);}.leftContentItem .itemImg .leftContentImg:nth-child(3){ transform: rotateY(-90deg) translateZ(100px);}.leftContentItem .itemImg .leftContentImg:nth-child(4){ transform: rotateY(90deg) translateZ(100px);}.leftContentItem .itemImg .leftContentImg:nth-child(5){ transform: rotateX(90deg) translateZ(100px);}.leftContentItem .itemImg .leftContentImg:nth-child(6){ transform: rotateX(-90deg) translateZ(100px);}@-webkit-keyframes imgRotate { from{ transform: translateZ(-100px) rotateX(0) rotateY(0); } to{ transform: translateZ(-100px) rotateX(360deg) rotateY(360deg); }}效果图主要就是设置景深perspective,然后对每个面旋转、平移正在努力学习中,若对你的学习有帮助,留下你的印记呗(点个赞咯^_^)往期好文推荐:webpack打包(有面试题)纯css实现瀑布流(multi-column多列及flex布局)画三角形判断ios和Android及PC端 ...

October 12, 2018 · 2 min · jiezi

前端每日实战:154# 视频演示如何创作一个眼冒金星的动画效果(A股就是这样,火眼金睛进去,眼冒金星出来)

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/OBgBJJ可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/c83BKt3源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 9 个子元素:<div class=‘container’> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: black;}设置容器中子元素的布局方式,形成一个 3 * 3 的网格,其中 –columns 是网格每一边上的子元素数量:.container { display: grid; –columns: 3; grid-template-columns: repeat(var(–columns), 1fr);}定义子元素样式:.container span { width: 25px; height: 25px; color: lime; background-color: currentColor;}增加子元素的动画效果,总动画时长是 5 秒,其中第 1 秒(0% ~ 20%)有动画,其余 4 秒(20% ~ 100%)静止:.container span { transform: scale(0); animation: spin 5s linear infinite;}@keyframes spin { 0% { transform: rotate(0deg) scale(1); } 5%, 15% { transform: rotate(90deg) scale(0); background: white; } 17.5% { transform: rotate(180deg) scale(1); background-color: currentColor; } 20%, 100% { transform: rotate(90deg) scale(0); }}设置动画延时,使各子元素的动画随机延时 4 秒之内的任意时间:.container span { animation-delay: calc(var(–delay) * 1s);}.container span:nth-child(1) { –delay: 0.8 }.container span:nth-child(2) { –delay: 0.2 }.container span:nth-child(3) { –delay: 1.9 }.container span:nth-child(4) { –delay: 3.9 }.container span:nth-child(5) { –delay: 2.8 }.container span:nth-child(6) { –delay: 3.5 }.container span:nth-child(7) { –delay: 1.5 }.container span:nth-child(8) { –delay: 2.3 }.container span:nth-child(9) { –delay: 1.7 }至此,静态效果完成,接下来批量处理 dom 元素。引入 d3 库:<script src=“https://d3js.org/d3.v5.min.js"></script>删除掉 css 文件中的 –columns 变量声明,用 d3 为变量赋值:const COLUMNS = 3;d3.select(’.container’) .style(’–columns’, COLUMNS);删除掉 html 文件中的 <span> 子元素,用 d3 动态生成:d3.select(’.container’) .style(’–columns’, COLUMNS) .selectAll(‘span’) .data(d3.range(COLUMNS * COLUMNS)) .enter() .append(‘span’);删除掉 css 文件中的 –delay 变量声明,用 d3 为变量生成随机数:d3.select(’.container’) .style(’–columns’, COLUMNS) .selectAll(‘span’) .data(d3.range(COLUMNS * COLUMNS)) .enter() .append(‘span’) .style(’–delay’, () => Math.random() * 4);最后,把边长改为 15,生成更多的子元素,加强视觉效果:const COLUMNS = 15;大功告成! ...

October 12, 2018 · 2 min · jiezi

图解一下啥是CSS堆叠上下文,啥是CSS堆叠层叠顺序,让你对css的疑惑少一点?

CSS 堆叠上下文是啥?我们有一个基本样式的 div,样式如下:div{ width: 200px; height: 200px; border:10px solid red; padding:15px; margin:12px;}效果如下:这边有个问题是: border 和 background是什么关系 ?这边有两个选项:平行的border 更靠近用户background 更靠近用户你们会选择哪个呢?其实弄懂这个很简单的,我们只需要把 border 设置成半透明就知道答案啦border:10px solid rgba(255, 0, 0, 0, .3);从运行结果就可以看出,红色透着绿色,所以是 border 更靠近用户 。 这时候你就知道div 不是平的,在垂直屏幕上也是有层次关系的,那这个层次关系就叫做堆叠上下文。接着我们在 div 里面写个 ‘你好,世界’,效果如下:这里又引发了一个问题,这个 ‘你好,世界’, 是在哪层了,是在 border 上还是在 border 与 background 之间呢?这边我们只需要把’你好’移动到border上就可知道原因了,那怎么把文字移动过去呢?这边我们用 text-indent ,样式如下:div{ width: 200px; height: 200px; border:10px solid rgb(255, 0, 0); padding:15px; margin:12px; background-color: green; text-indent: -20px;}效果如下:从运行效果就可以看了,文字是在 border上面的,所以文字区域(内联元素)是更靠近用户的那如果div 里面还有一个 div 呢?代码结构如下: // html <div class=“parent”> 你好,CSS世界 <div class=“child”></div> </div> // css .parent{ width: 200px; height: 200px; border:10px solid rgb(255, 0, 0); padding:15px; margin:12px; background-color: green; text-indent: -20px; } .child{ height: 20px; background:purple; }效果如下:又引发了一个问题,紫色区域是比文字区域高还是相反呢?那怎么验证这个问题了?我们只要把里面的 div 往上移动就行,注意这里不能用 position因为为改变层级结构, 我们只要用 margin-top 就行了,如: margin-top:-20px;效果如下:你会发现文字区域是在上面的。这边就得出一个结论:如果div里面有块级元素,块级元素是盖不住内联元素的,换句话说内联元素离用户更近那如果里面div有文字呢? 这时我们需要 写几个字,效果如下:你会发现 子元素的文字区域会盖住父元素的文字区域,所以这边又有一个小的结论:文字区域后出现的会覆盖前出现的。浮动元素来一个基本结构: // html <div class=“parent”> 你好 <div class=“float”> </div> </div> // css.parent{ width: 200px; height: 200px; border:10px solid rgb(255, 0, 0); padding:15px; margin:12px; background-color: green; color: aliceblue;}.float{ height: 40px; width: 40px; background:purple; float: left;}效果如下:上面代码就不解释了,你们肯定都 知道 ?按上面的套路,这里同样还是那个问题:你好在上面呢还是这个 float 元素呢?要验证这个问题,同样使用 text-indent 那文字向左动点,这里我直接 上效果了:从效果图,我们可以得出 文字区域是在 浮云元素上面的。那浮动元素是在 文字区域与内部块级元素之间呢,还是内部块级与border元素之间呢?换句话说就是 浮动元素与块级元素哪个离用户更近?我们直接在父级元素写一个 child: // hmtl <div class=“parent”> 你好 <div class=“float”></div> <div class=“child”></div> </div> // css .child{ height: 20px; background: black;}效果如下:从上可以看出浮云元素盖住了 child元素,说明浮动元素的层级是比块级元素高的。即浮动元素是在文字区域与块级元素之间的。那浮动元素里面的文字与外面的文字是怎么样的呢?这边我直接在浮动里面加了 float文字,效果如下:你会发现 浮动里面的文字是盖不住浮动外面文字的。绝对定位元素在上面的基础上我们增加一个 relative 元素,如下: // htmk <div class=“parent”> 你好 <div class=“float”>floatt</div> <div class=“child”></div> <div class=“relative”></div> </div> // css.relative{ width: 100px; height: 100px; background: pink; margin-top: -15px;}效果如下:这时我们给类relative 加上一个:position:relative;效果如下:你会发现 relative 元素盖住了浮动元素,这说明 给元素加一个 relative 定位会增加对应的一个层级。检查 relative 元素,会看到:加了 position:relative定位会多了一个 z-index:auto 的东西,实际上你定位,都是按z-index来计算的。这里我们给没有定位的 child元素加上一个z-index: <div class=“parent”> 你好 <div class=“float”>floatt</div> <div class=“child” style=“z-index:99999”></div> <div class=“relative”></div> </div>效果如下:你会发现 child 元素并没有盖住 relative 元素!这边直接 给了结论了:z-index 只有在 position:relative|absolute才有效果,如果都是relative,z-index一样,那么后面会盖前面,z-index值大的会盖住小的。我们接着在原有上加一个relative2,样式如下:.relative2{ width: 100px; height: 150px; background: gold; margin-top: -15px; position: relative;}效果如下:此时给 relative2 加上一个 z-index:-1,在看又得出一个结论:z-index为负值时,是位于 background下面的这时,我们给.parent元素添加以下两个样式: position: relative; z-index: 0; 这时的效果如下:这时奇怪的事情就出现了,z-index: -1 的跑到上面来了。MDN上有对什么堆叠给出了一些内容,如下 :其实我们给.parent元素设置z-index:0 ,根据MDN说的,我们其实已经 创造一个层叠上下文 。那什么是堆叠上下文?下面是张鑫旭一段原文:其实这跟美国一个大法官说的一句话很像:我不知道什么色情,但当我看到它是我就知道什么是色情。 CSS堆叠上下文也是类似的道理,你很难说出什么是CSS堆叠上下文,但只要它满足MDN列出的几种情况,它就是CSS堆叠上下文。CSS堆叠层叠顺序CSS堆叠上下文是有一个垂直屏幕上有一个上关系的,它们的关系如下:所以这就解释为什么z-index为负值的时候,它会在 background上面,因为我们 z-index:0 时就创建一个CSS堆叠上下文。CSS堆叠上下文作用下面给一个基本的内容: // html <div class=“parent”> <div class=“a relative”>a <div class=“a1”>a1</div> </div> <div class=“b relative”>b <div class=“b1”>b1</div> </div> </div> // css .parent{ width: 200px; height: 200px; border:10px solid rgb(255, 0, 0); padding:15px; margin:12px; background-color: green;}.relative{ width:100px; height:100px; background: orange; position: relative; border:1px solid red;}.a1{ position: relative; background:green;}.b1{ position: relative; background:red;}效果如下:接着我们在b1在添加以下样式: margin-top: -90px;b1会盖住a1,这个我们应该知道是什么原因了吧?因为a1 b1都是块级元素,后面会盖住前面的,没毛病!那么 a1 和 b1 的CSS堆叠上下文是谁?我们可以MDN给出的第一句:根元素,所以a1 和 b1的CSS堆叠上下文就是Html接着给a1以下样式: z-index: 2; 接着给b1以下样式:z-index: 0; 效果如下:a1跑到b1上面了,这个很好理解,因为 a1 的z-index:2 比 b1的z-index:0 在,所以a1在上面。现在有一个问题,a1是永远盖住b1吗?这边你可能会说,a1 的z-index:2比 b1的 z-index:0 永远都大,当然会盖住b1呀!是这样吗?我们试着改变一下CSS堆叠上下文。我们分别给a 和 b各做一个CSS堆叠上下文: 如下:.a{ position: relative; z-index: 1;}.b{ position: relative; z-index: 1;}效果如下:先分析a 和 b它们是谁覆盖谁,因为 两个定位和z-index都一样所以 b 会覆盖 a。还有一个现象有没有发现, b1 盖住了 a1? 明明 a1 的 z-index 大于 b1,这是为什么?为什么小的会盖住大的?为什么?因为 b 比 a 高一点,所以 b 里面的内容都会比 a 高一点。这就是 CSS堆叠上下文一个特性。 比如说阿里巴巴有一个奇怪的部门叫做政委,是由马云等一些创始人组成的。在这个部门里面,你是不是都比其它部门要高级点。所以 b1 虽然在 b 里面等级为0,在 b 是高级的一个部门,就是可以压过你 a 这个部门里面的 2 级的人。今天说这些了,如果还太明白可以看看以下的内容 :张鑫旭的深入理解CSS中的层叠上下文和层叠顺序MDN 文档更多内容可以关注下面这个很少人喜欢的一个笨笨的人一个笨笨的码农,我的世界只能终身学习 ...

October 12, 2018 · 2 min · jiezi

前端每日实战 2018 年 9 月份项目汇总(共 26 个项目)

过往项目2018 年 8 月份项目汇总(共 29 个项目)2018 年 7 月份项目汇总(共 29 个项目)2018 年 6 月份项目汇总(共 27 个项目)2018 年 5 月份项目汇总(共 30 个项目)2018 年 4 月份项目汇总(共 8 个项目)2018 年 9 月份发布的项目《前端每日实战》专栏每天分解一个前端项目,用视频记录编码过程,再配合详细的代码解读,是学习前端开发的活的参考书!124# 视频演示如何用纯 CSS 创作一只纸鹤125# 视频演示如何用纯 CSS 创作一个失落的人独自行走的动画126# 视频演示如何用纯 CSS 创作小球变矩形背景的按钮悬停效果127# 视频演示如何用纯 CSS 创作一个圆环旋转错觉动画128# 视频演示如何用纯 CSS 创作一个“女神来了,快让路”的动画129# 视频演示如何用纯 CSS 创作一个条纹错觉动画130# 视频演示如何用 CSS 在线字体和 D3 创作一个 Google & googol 信息图131# 视频演示如何用纯 CSS 创作一把剪刀132# 视频演示如何用纯 CSS 创作一只思考的手133# 视频演示如何用 CSS 和 GSAP 创作有多个关键帧的连续动画134# 视频演示如何用 CSS 和 GSAP 创作一个树枝发芽的 loader135# 视频演示如何用纯 CSS 创作一个悬停时右移的按钮特效136# 视频演示如何用 D3 和 GSAP 创作一个横条 loader137# 视频演示如何用纯 CSS 创作一个抽象的水波荡漾的动画138# 视频演示如何用纯 CSS 创作一张 iPhone 价格信息图139# 视频演示如何用 CSS 和 D3 创作光斑粒子交相辉映的动画140# 视频演示如何用纯 CSS 创作文本的淡入动画效果141# 视频演示如何用 CSS 的 Grid 布局创作一枚小狗邮票142# 视频演示如何用 CSS 的 Grid 布局创作一枚小鸡邮票143# 视频演示如何用 CSS 的 Grid 布局创作一枚小松鼠邮票144# 视频演示如何用 D3 和 GSAP 创作一个集体舞动画145# 视频演示如何用纯 CSS 创作一个电源开关控件146# 视频演示如何用纯 CSS 创作一个脉动 loader147# 视频演示如何用纯 CSS 创作透视按钮的悬停特效148# 视频演示如何用纯 CSS 创作从按钮两侧滑入装饰元素的悬停特效149# 视频演示如何用纯 CSS 创作一个宝路薄荷糖的动画 ...

October 8, 2018 · 1 min · jiezi

前端每日实战:151# 视频演示如何用纯 CSS 创作超能陆战队的大白

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/ReGRaO可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cEJDKSg源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读整个人物分为 3 部分:头、身体、腿,下面按照这个顺序分别画出,先画头部。定义 dom,容器 .baymax 表示大白,head 表示头部:<div class=“baymax”> <div class=“head”> <div class=“eyes”></div> </div></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: rgba(176, 0, 0, 0.75);}定义容器尺寸和子元素对齐方式:.baymax { width: 30em; height: 41em; font-size: 10px; display: flex; justify-content: center; position: relative;}画出头部轮廓:.head { position: absolute; width: 9em; height: 6em; background-color: white; border-radius: 50%; box-shadow: inset 0 -1.5em 3em rgba(0, 0, 0, 0.2), 0 0.5em 1.5em rgba(0, 0, 0, 0.2);}画出双眼中间的线条:.head .eyes { position: absolute; width: 4.8em; height: 0.1em; background-color: #222; top: 2.3em; left: calc((9em - 4.8em) / 2);}画出双眼:.head .eyes::before,.head .eyes::after { content: ‘’; position: absolute; width: 0.8em; height: 0.9em; background-color: #222; border-radius: 50%; top: -0.3em;}.head .eyes::after { right: 0;}接下来画身体。html 文件中增加身体的 dom 元素:<div class=“baymax”> <div class=“head”> <!– 略 –> </div> <div class=“body”> <div class=“chest”> <span class=“button”></span> </div> <div class=“belly”></div> <div class=“left arm”> <div class=“fingers”></div> </div> <div class=“right arm”> <div class=“fingers”></div> </div> </div></div>定义身体的宽度:.body { position: absolute; width: inherit;}画出胸部:.body .chest { position: absolute; width: 19em; height: 26em; background-color: white; top: 4em; left: calc((100% - 19em) / 2); border-radius: 50%; z-index: -1;}画出胸前的按钮:.body .chest .button { position: absolute; width: 2em; height: 2em; background-color: white; border-radius: 50%; top: 4em; right: 4em; box-shadow: inset 0 -0.5em 0.8em rgba(0, 0, 0, 0.15), 0.2em 0.3em 0.2em rgba(0, 0, 0, 0.05); filter: opacity(0.75);}画出肚皮:.body .belly { position: absolute; width: 24em; height: 31em; background-color: white; top: 5.5em; left: calc((100% - 24em) / 2); border-radius: 50%; z-index: -2; box-shadow: inset 0 -2.5em 4em rgba(0, 0, 0, 0.15), 0 0.5em 1.5em rgba(0, 0, 0, 0.25);}定义胳膊的高度起点:.body .arm { position: absolute; top: 7.5em;}胳膊分为肘以上的部分和肘以下的部分。先设计这两段的共有属性:.body .arm::before,.body .arm::after { content: ‘’; position: absolute; background-color: white; border-radius: 50%; transform-origin: top; z-index: -3;}再用伪元素分别画出这两部分:.body .arm::before { width: 9em; height: 20em; left: 7em; transform: rotate(30deg);}.body .arm::after { width: 8em; height: 15em; left: -0.8em; top: 9.5em; transform: rotate(-5deg); box-shadow: inset 0.4em -1em 1em rgba(0, 0, 0, 0.2);}定义两根手指的共有属性:.body .arm .fingers::before,.body .arm .fingers::after { content: ‘’; position: absolute; width: 1.8em; height: 4em; background-color: white; border-radius: 50%; transform-origin: top;}用伪元素分别画出两根手指:.body .arm .fingers::before { top: 22em; left: 2em; transform: rotate(-25deg); box-shadow: inset 0.2em -0.4em 0.4em rgba(0, 0, 0, 0.4);}.body .arm .fingers::after { top: 21.5em; left: 4.8em; transform: rotate(-5deg); box-shadow: inset -0.2em -0.4em 0.8em rgba(0, 0, 0, 0.3); z-index: -3;}至此,完成了右胳膊。把右胳膊复制并水平翻转,即可得到左胳膊:.body .arm.left { transform: scaleX(-1); right: 0; z-index: -3;}接下来画腿部。在 html 文件中增加腿的 dom 元素:<div class=“baymax”> <div class=“head”> <!– 略 –> </div> <div class=“body”> <!– 略 –> </div> <div class=“left leg”></div> <div class=“right leg”></div></div>画出腿的内侧:.leg { position: absolute; width: 5em; height: 16em; bottom: 0; background-color: white; border-bottom-right-radius: 1.5em; left: 10em; box-shadow: inset -0.7em -0.6em 0.7em rgba(0, 0, 0, 0.1); z-index: -3;}画出腿的外侧:.leg::before { content: ‘’; position: absolute; width: 2.5em; height: inherit; background-color: white; border-bottom-left-radius: 100%; left: -2.5em; box-shadow: inset 0.7em 1.5em 0.7em rgba(0, 0, 0, 0.4);}至此,完成了右腿。把右腿复制并水平翻转,即可得到左腿:.leg.left { transform-origin: right; transform: scaleX(-1);}大功告成! ...

October 7, 2018 · 3 min · jiezi

前端每日实战:152# 视频演示如何用纯 CSS 创作一个圆点错觉效果

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/gBwzKR可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/ca82VAM源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读此项目无用户自定义的 dom 元素,利用系统默认的 <body> 元素作为容器。定义页面尺寸,背景设置为黑色:body { margin: 0; width: 100vw; height: 100vh; background-color: black;}用线性渐变画出一横一竖二条灰色的细线:body { margin: 0; width: 100vw; height: 100vh; background-color: black; background-image: linear-gradient( to bottom, #555 2vmin, transparent 2vmin ), linear-gradient( to right, #555 2vmin, transparent 2vmin );}用径向渐变在左上角画一个白色的圆点:body { margin: 0; width: 100vw; height: 100vh; background-color: black; background-image: radial-gradient( circle at 1vmin 1vmin, white 1vmin, transparent 1vmin ), linear-gradient( to bottom, #555 2vmin, transparent 2vmin ), linear-gradient( to right, #555 2vmin, transparent 2vmin );}平铺背景:body { margin: 0; width: 100vw; height: 100vh; background-color: black; background-image: radial-gradient( circle at 1vmin 1vmin, white 1vmin, transparent 1vmin ), linear-gradient( to bottom, #555 2vmin, transparent 2vmin ), linear-gradient( to right, #555 2vmin, transparent 2vmin ); background-size: 10vmin 10vmin;}为避免圆点紧贴在左侧和顶部,为背景增加一点偏移量:body { margin: 0; width: 100vw; height: 100vh; background-color: black; background-image: radial-gradient( circle at 1vmin 1vmin, white 1vmin, transparent 1vmin ), linear-gradient( to bottom, #555 2vmin, transparent 2vmin ), linear-gradient( to right, #555 2vmin, transparent 2vmin ); background-size: 10vmin 10vmin; background-position: 5vmin 5vmin;}现在,如果视线在页面中移动,就会看到黑色小圆点,这实际上是错觉。大功告成! ...

October 7, 2018 · 1 min · jiezi

CSS魔法堂:改变单选框颜色就这么吹毛求疵!

前言 是否曾经被业务提出"能改改这个单选框的颜色吧!让它和主题颜色搭配一下吧!",然后苦于原生不支持换颜色,最后被迫自己手撸一个凑合使用。若抛开input[type=radio]重新开发一个,发现要模拟选中、未选中、不可用等状态很繁琐,而涉及单选框组就更烦人了,其实我们可以通过label、::before、:checked和tabindex,然后外加少量JavaScript脚本就能很好地模拟出一个样式更丰富的“原生”单选框。下面我们一起来尝试吧!单选框了解一下 由于我们的目标是改变单选框颜色,其他外观特征和行为与原来的单选框一致,那么我们就必须先了解单选框原来的外观特征和行为主要有哪些。1.外观特征1.1.常态样式margin: 3px 3px 0px 5px;border: none 0;padding: 0;box-sizing: border-box;display: inline-block;line-height: normal;position: static;注意:外观上我们必须要保证布局特性和原生的一致,否则采用自定义单选框替换后很大机会会影响整体的布局,最后导致被迫调整其他元素的布局特性来达到整体的协调,从而扩大了修改范围。1.2.获得焦点的样式outline-offset: 0px;outline: -webkit-focu-ring-color auto 5px;注意:这里的获取焦点的样式仅通过键盘Tab键才生效,若通过鼠标点击虽然单选框已获得焦点,但上述样式并不会生效。1.3.设置为disabled的样式color: rgb(84, 84, 84);2.行为特征 单选框的行为特征,明显就是选中与否,及选中状态的改变事件,因此我们必须保持对外提供change事件。 另外值得注意的是,当通过键盘的Tab键让单选框获得焦点后,再按下Space键则会选中该单选框。 有了上述的了解,我们可以开始着手撸代码了!少废话,撸代码上图中左侧就是原生单选框,右侧为我们自定义的单选框。从上到下依次为未选中、选中、获得焦点和disabled状态的样式。CSS部分label.radio { /* 保证布局特性保持一致 / margin: 3px 3px 0px 5px; display: inline-block; box-sizing: border-box; width: 12px; height: 12px;}.radio__appearance{ display: block; / 设置为block则不受vertical-align影响,从而不会意外影响到.radio的linebox高度 / position: relative; box-shadow: 0 0 0 1px tomato; / box-shadow不像border那样会影响盒子的框高 / border-radius: 50%; height: 90%; width: 90%; text-align: center;}label.radio [type=radio] + .radio__appearance::before{ content: “”; display: block; border-radius: 50%; width: 85%; height: 85%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); transition: background .3s;}label.radio [type=radio]:checked + .radio__appearance::before{ background: tomato;}label.radio [type=radio][disabled] + .radio__appearance{ opacity: .5;}label.radio:focus{ outline-offset: 0px; outline: #999 auto 5px;}/ 通过鼠标单击获得焦点时,outline效果不生效 /label.radio.clicked{ outline: none 0;}/ 自定义单选框的行为主要是基于原生单选框的,因此先将原生单选框隐藏 */label.radio input { display: none;}HTML部分<!– 未选中状态 –><label class=“radio” tabindex=“0”> <input type=“radio” name=“a”> <i class=“radio__appearance”></i></label><br><!– 选中状态 –><label class=“radio” tabindex=“0”> <input type=“radio” name=“a” checked> <i class=“radio__appearance”></i></label><br><!– disabled状态 –><label class=“radio”> <input type=“radio” name=“a” disabled> <i class=“radio__appearance”></i></label>JavaScript部分var radios = document.querySelectorAll(".radio")radios.forEach(radio => { // 模拟鼠标点击后:focus样式无效 radio.addEventListener(“mousedown”, e => { var tar = e.currentTarget tar.classList.add(“clicked”) var fp = setInterval(function(){ if (document.activeElement != tar){ tar.classList.remove(“clicked”) clearInterval(fp) } }, 400) }) // 模拟通过键盘获得焦点后,按Space键执行选中操作 radio.addEventListener(“keydown”, e => { if (e.keyCode === 32){ e.target.click() } })})这个实现有3个注意点:通过label传递鼠标点击事件到关联的input[type=radio],因此可以安心隐藏单选框又可以利用单选框自身特性。但由于label控件自身的限制,如默认不是可获得焦点元素,因此无法传递键盘按键事件到单选框,即使添加tabindex特性也需手写JS来实现;当tabindex大于等于0时表示该元素可以获得焦点,为0时表示根据元素所在位置安排获得焦点的顺序,而大于0则表示越小越先获得焦点;由于单选框的display为inline-block,因此单选框将影响line box高度。当自定义单选框内元素采用inline-block时,若vertical-align设置稍有不慎就会导致内部元素所在的line box被撑高,从而导致自定义单选框所在的line box高度变大。因此这里采用将内部元素的display均设置为block的做法,直接让vertical-align失效,提高可控性。总结 对于复选框我们可以稍加修改就可以了,然后通过VUE、React等框架稍微封装一下提供更简约的API,使用起来就更方便了。 尊重原创,转载请注明来自:https://www.cnblogs.com/fsjoh… ^_^肥仔John ...

October 4, 2018 · 1 min · jiezi

前端每日实战:150# 视频演示如何用 CSS 和 D3 创作一个集体舞动画

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/yRYOwq可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cBZ3Nt6源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 1 个 .square 子容器,子容器中包含 4 个 <span>,每个 <span> 代表一个对角扇形:<figure class=“container”> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div></figure>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #222;}设置容器的尺寸单位,1em 等于 8px:.container { font-size: 8px;}子容器中的 4 个 <span> 不设宽高,只设边框,其中第 1 个和第 4 个 <span> 只取左右边框,第 2 个和第 3 个 <span> 只取上下边框:.square span { display: block; border: 2.5em solid transparent; color: #ddd;}.square span:nth-child(1),.square span:nth-child(4) { border-left-color: currentColor; border-right-color: currentColor;}.square span:nth-child(2),.square span:nth-child(3) { border-top-color: currentColor; border-bottom-color: currentColor;}把边框改为圆弧:.square span { border-radius: 50%;}在子容器中用 grid 布局把 4 个 <span> 设置为 2 * 2 的网格:.square { display: grid; grid-template-columns: repeat(2, 1fr); grid-gap: 0.2em; padding: 0.1em;}旋转 4 个 <span>,使它们围合成一个正方形,看起来像一个花朵,算式的结果是 45 度,写成这样是为了和接下来的动画的算式的形式保持一致:.square span { transform: rotate(calc(45deg + 90deg * 0));}增加让 <span> 旋转的动画,整个动画过程旋转 4 次,每次旋转 90 度,4 次旋转之后即返回原位:.square span { animation: rotation 2s ease-in-out infinite;}@keyframes rotation { 0% { transform: rotate(calc(45deg + 90deg * 0)); } 25% { transform: rotate(calc(45deg + 90deg * 1)); } 50% { transform: rotate(calc(45deg + 90deg * 2)); } 75% { transform: rotate(calc(45deg + 90deg * 3)); } 100% { transform: rotate(calc(45deg + 90deg * 4)); }}使其中 2 个 <span> 朝相反的方向运动:.square span:nth-child(2),.square span:nth-child(3) { animation-direction: reverse;}至此,一个 .square 子容器的动画已经完成,接下来制作 4 个 .square 的动画。在 dom 中再增加 3 组 .square 子容器:<figure class=“container”> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div></figure>用 grid 布局把 4 个 .square 布局成网格状,变量 –columns 是网格的边长,即每边有 2 个 .square 子容器:.container { display: grid; –columns: 2; grid-template-columns: repeat(var(–columns), 1fr);}现在看起来好像是有几个黑色的小方块在不停地移动,当 dom 元素越多时,动画效果看起来就越壮观,就像集体舞一样,人越多越有气势。接下来用 d3 批量增加 dom 的元素。引入 d3 库:<script src=“https://d3js.org/d3.v5.min.js"></script>声明一个 COLUMNS 常量,表示网格的边长:const COLUMNS = 2;删除掉 html 文件中的 .square 子元素,改为用 d3 动态创建:d3.select(’.container’) .selectAll(‘div’) .data(d3.range(COLUMNS * COLUMNS)) .enter() .append(‘div’) .attr(‘class’, ‘square’);继续用连缀语法增加 <span> 子元素:d3.select(’.container’) .selectAll(‘div’) .data(d3.range(COLUMNS * COLUMNS)) .enter() .append(‘div’) .attr(‘class’, ‘square’) .selectAll(‘span’) .data(d3.range(4)) .enter() .append(‘span’);删除掉 css 文件中的 –columns 变量声明,改为用 d3 动态声明:d3.select(’.container’) .style(’–columns’, COLUMNS) /略/最后,把边长改为 4,即让 16 个 .square 一起动画:const COLUMNS = 4;大功告成! ...

October 4, 2018 · 2 min · jiezi

前端每日实战:150# 视频演示如何用 CSS 和 D3 创作一个集体舞动画

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/yRYOwq可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cBZ3Nt6源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 1 个 .square 子容器,子容器中包含 4 个 <span>,每个 <span> 代表一个对角扇形:<figure class=“container”> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div></figure>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #222;}设置容器的尺寸单位,1em 等于 8px:.container { font-size: 8px;}子容器中的 4 个 <span> 不设宽高,只设边框,其中第 1 个和第 4 个 <span> 只取左右边框,第 2 个和第 3 个 <span> 只取上下边框:.square span { display: block; border: 2.5em solid transparent; color: #ddd;}.square span:nth-child(1),.square span:nth-child(4) { border-left-color: currentColor; border-right-color: currentColor;}.square span:nth-child(2),.square span:nth-child(3) { border-top-color: currentColor; border-bottom-color: currentColor;}把边框改为圆弧:.square span { border-radius: 50%;}在子容器中用 grid 布局把 4 个 <span> 设置为 2 * 2 的网格:.square { display: grid; grid-template-columns: repeat(2, 1fr); grid-gap: 0.2em; padding: 0.1em;}旋转 4 个 <span>,使它们围合成一个正方形,看起来像一个花朵,算式的结果是 45 度,写成这样是为了和接下来的动画的算式的形式保持一致:.square span { transform: rotate(calc(45deg + 90deg * 0));}增加让 <span> 旋转的动画,整个动画过程旋转 4 次,每次旋转 90 度,4 次旋转之后即返回原位:.square span { animation: rotation 2s ease-in-out infinite;}@keyframes rotation { 0% { transform: rotate(calc(45deg + 90deg * 0)); } 25% { transform: rotate(calc(45deg + 90deg * 1)); } 50% { transform: rotate(calc(45deg + 90deg * 2)); } 75% { transform: rotate(calc(45deg + 90deg * 3)); } 100% { transform: rotate(calc(45deg + 90deg * 4)); }}使其中 2 个 <span> 朝相反的方向运动:.square span:nth-child(2),.square span:nth-child(3) { animation-direction: reverse;}至此,一个 .square 子容器的动画已经完成,接下来制作 4 个 .square 的动画。在 dom 中再增加 3 组 .square 子容器:<figure class=“container”> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div> <div class=“square”> <span></span> <span></span> <span></span> <span></span> </div></figure>用 grid 布局把 4 个 .square 布局成网格状,变量 –columns 是网格的边长,即每边有 2 个 .square 子容器:.container { display: grid; –columns: 2; grid-template-columns: repeat(var(–columns), 1fr);}现在看起来好像是有几个黑色的小方块在不停地移动,当 dom 元素越多时,动画效果看起来就越壮观,就像集体舞一样,人越多越有气势。接下来用 d3 批量增加 dom 的元素。引入 d3 库:<script src=“https://d3js.org/d3.v5.min.js"></script>声明一个 COLUMNS 常量,表示网格的边长:const COLUMNS = 2;删除掉 html 文件中的 .square 子元素,改为用 d3 动态创建:d3.select(’.container’) .selectAll(‘div’) .data(d3.range(COLUMNS * COLUMNS)) .enter() .append(‘div’) .attr(‘class’, ‘square’);继续用连缀语法增加 <span> 子元素:d3.select(’.container’) .selectAll(‘div’) .data(d3.range(COLUMNS * COLUMNS)) .enter() .append(‘div’) .attr(‘class’, ‘square’) .selectAll(‘span’) .data(d3.range(4)) .enter() .append(‘span’);删除掉 css 文件中的 –columns 变量声明,改为用 d3 动态声明:d3.select(’.container’) .style(’–columns’, COLUMNS) /略/最后,把边长改为 4,即让 16 个 .square 一起动画:const COLUMNS = 4;大功告成! ...

October 2, 2018 · 2 min · jiezi

前端每日实战:149# 视频演示如何用纯 CSS 创作一个宝路薄荷糖的动画

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/oagrvz可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cRbqJcD源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,只有 1 个元素:<div class=“spinner”></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: silver;}定义容器尺寸:.spinner { width: 50vmin; height: 50vmin; position: relative;}用 before 伪元素画出 1 个像宝路薄荷糖状的黑色圆环:.spinner::before { content: ‘’; position: absolute; box-sizing: border-box; width: inherit; height: inherit; border: 12.5vmin solid; border-radius: 50%;}接下来制作动画效果。设置透视景深:body { perspective: 400px;}让圆环在 z 轴上运动:.spinner::before { animation: spin 1.5s ease-in-out infinite both reverse;}@keyframes spin { 0%, 100% { transform: translateZ(10vmin); } 60% { transform: translateZ(-10vmin); }}让圆环在 z 轴距离较大时稍稍倾斜:@keyframes spin { 0%, 100% { transform: translateZ(10vmin) rotateX(25deg); } 60% { transform: translateZ(-10vmin); }}增加缩放效果:@keyframes spin { 0%, 100% { transform: translateZ(10vmin) rotateX(25deg); } 33% { transform: translateZ(-10vmin) scale(0.4); } 60% { transform: translateZ(-10vmin); }}用 after 伪元素再画出一个白色的圆环,并且让它的动画延迟动画总长的一半时间:.spinner::before,.spinner::after { /略/ animation: spin 1.5s ease-in-out infinite both reverse;}.spinner::after { border-color: white; animation-delay: -0.75s;}接下来制作容器的动画效果,为了不受子元素动画的影响,先暂时屏蔽伪元素的动画效果。.spinner::before,.spinner::after { /* animation: spin 1.5s ease-in-out infinite both reverse; */}增加容器沿 x 轴旋转的动画效果,动画时间为子元素动画时间的2倍:.spinner { animation: wobble 3s ease-in-out infinite;}@keyframes wobble { 0%, 100% { transform: rotateX(15deg); } 50% { transform: rotateX(60deg); }}增加容器沿 y 轴旋转的动画效果:@keyframes wobble { 0%, 100% { transform: rotateX(15deg) rotateY(60deg); } 50% { transform: rotateX(60deg) rotateY(-60deg); }}增加容器整体旋转的动画效果:@keyframes wobble { 0%, 100% { transform: rotateX(15deg) rotateY(60deg); } 50% { transform: rotateX(60deg) rotateY(-60deg) rotate(180deg); }}打开子元素的动画效果,使子元素的动画效果和容器的动画效果叠加:.spinner::before,.spinner::after { animation: spin 1.5s ease-in-out infinite both reverse;}最后,使子元素在 3d 空间上运动:.spinner { transform-style: preserve-3d;}大功告成! ...

October 1, 2018 · 1 min · jiezi

CSS魔法堂:display:none与visibility:hidden的恩怨情仇

前言 还记得面试时被问起"请说说display:none和visibility:hidden的区别"吗?是不是回答完display:none不占用原来的位置,而visibility:hidden保留原来的位置后,面试官就会心一笑呢?其实不止那么简单呢!本文我们将一起深究它俩的恩怨情仇,下次面试时我们可以回答得更出彩!深入display:none 我们都清楚当元素设置display:none后,界面上将不会显示该元素,并且该元素不占布局空间,但我们仍然可以通过JavaScript操作该元素。但为什么会这样呢? 这个涉及到浏览器的渲染原理:浏览器会解析HTML标签生成DOM Tree,解析CSS生成CSSOM,然后将DOM Tree和CSSOM合成生成Render Tree,元素在Render Tree中对应0或多个盒子,然后浏览器以盒子模型的信息布局和渲染界面。而设置为display:none的元素则在Render Tree中没有生成对应的盒子模型,因此后续的布局、渲染工作自然没它什么事了,至于DOM操作还是可以的。 但除了上面的知识点外,还有以下8个点我们需要注意的1.原生默认display:none的元素其实浏览器原生元素中有不少自带display:none的元素,如link,script,style,dialog,input[type=hidden]等.2.HTML5中新增hidden布尔属性,让开发者自定义元素的隐藏性/* 兼容原生不支持hidden属性的浏览器 /[hidden]{ display: none;}<span hidden>Hide and Seek: You can’t see me!</span>3.父元素为display:none,子孙元素也难逃一劫.hidden{ display: none;}.visible{ display: block;}** START <div class=“hidden”> I’m parent! <div class=“visible”> I’m son! </div></div> END 浏览器直接显示为 START ****** END ***4.无法获取焦点本来无一盒,何处惹焦点呢^^即使通过tab键也是没办法的<!– 真心不会获得焦点 –><input type=“hidden”><div tabindex=“1” style=“display:none”>hidden</div>5.无法响应任何事件,无论是捕获、命中目标和冒泡阶段均不可以由于display:none的元素根本不会在界面上渲染,就是连1个像素的都不占,因此自然无法通过鼠标点击命中,而元素也无法获取焦点,那么也不能成为键盘事件的命中目标;而父元素的display为none时,子元素的display必定为none,因此元素也没有机会位于事件捕获或冒泡阶段的路径路径上,因此display:none的元素无法响应事件。6.不耽误form表单提交数据虽然我们无法看到display:none的元素,但当表单提交时依然会将隐藏的input元素的值提交上去。<form> <input type=“hidden” name=“id”> <input type=“text” name=“gguid” style=“display:none”></form>7.CSS中的counter会忽略display:none的元素.start{ counter-reset: son 0;}.son{ counter-increment: son 1;}.son::before{ content: counter(son) “. “;}<div class=“start”> <div class=“son”>son1</div> <div class=“son” style=“display:none”>son2</div> <div class=“son”>son3</div></div>结果就是:1. son12. son38.Transition对display的变化不感冒详情请参考CSS魔法堂:Transition就这么好玩9.display变化时将触发reflow撇开display:none,我们看看display:block表示元素位于BFC中,而display:inline则表示元素位于IFC中,也就是说display的用于就是设置元素所属的布局上下文,若修改display值则表示元素采用的布局方式已发生变化,不触发reflow才奇怪呢!深入visibility visibility有两个不同的作用用于隐藏表格的行和列用于在不触发布局的情况下隐藏元素4个有效值1.visible 没什么好说的,就是在界面上显示。2.hidden 让元素在见面上不可视,但保留元素原来占有的位置。3.collapse 用于表格子元素(如tr,tbody,col,colgroup)时效果和display:none一样,用于其他元素上时则效果与visibility:hidden一样。不过由于各浏览器实现效果均有出入,因此一般不会使用这个值。4.inherit 继承父元素的visibility值。对比清楚display:none和visibility:hidden 上面我们已经对display:none列出8点注意事项,那么我们仅需对照它逐一列出visibility的不就清晰可见了吗?1.父元素为visibility:hidden,而子元素可以设置为visibility:visible并且生效div{ border: solid 2px blue;}.visible{ visibility: visible;}.hidden{ visibility: hidden;}<div class=“hidden”> I’m Parent. <div class=“visible”> I’m Son. </div></div>结果:2.和display:none一样无法获得焦点3.可在冒泡阶段响应事件由于设置为visibility:hidden的元素其子元素可以为visibility:visible,因此隐藏的元素有可能位于事件冒泡的路径上因此下面代码中,将鼠标移至.visible时,.hidden会响应hover事件显示。div{ border: solid 2px blue;}.visible{ visibility: visible;}.hidden{ visibility: hidden;}.hidden:hover{ visibility: visible;}<div class=“hidden”> I’m Parent. <div class=“visible”> I’m Son. </div></div>4.和display:none一样不妨碍form表单的提交5.CSS中的counter不会忽略6.Transition对visibility的变化有效7.visibility变化不会触发reflow由于从visible设置为hidden时,不会改变元素布局相关的属性,因此不会触发reflow,只是静静地和其他渲染变化一起等待浏览器定时重绘界面。总结 现在我们对display:none和visibility:hidden应该有更深入的了解了,下次面试时我们的答案会更丰富出彩哦! 尊重原创,转载请注意来自:https://www.cnblogs.com/fsjoh… 肥仔John^^引用https://css-tricks.com/almana…https://juejin.im/post/5b406f… ...

September 30, 2018 · 1 min · jiezi

前端每日实战:147# 视频演示如何用纯 CSS 创作透视按钮的悬停特效

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/qJEdKb可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cEJRKud源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器是一个无序列表,包含 4 个元素,代表 4 个按钮:<ul> <li>home</li> <li>products</li> <li>services</li> <li>contact</li></ul>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background: cornsilk;}去掉列表项前面的符号:ul { padding: 0; list-style-type: none;}设置按钮的边框和背景的样式,背景采用渐变色,但渐变的方向依次交替:ul li { box-sizing: border-box; width: 15em; height: 3em; font-size: 20px; border-radius: 0.5em; margin: 0.5em; box-shadow: 0 0 1em rgba(0,0,0,0.2);}ul li:nth-child(odd) { background: linear-gradient(to right, orange, tomato);}ul li:nth-child(even) { background: linear-gradient(to left, orange, tomato);}设置按钮上文字的样式,依次交替居左或居右:ul li { color: white; font-family: sans-serif; text-transform: capitalize; line-height: 3em;}ul li:nth-child(odd) { text-align: left; padding-left: 10%;}ul li:nth-child(even) { text-align: right; padding-right: 10%;}设置按钮的透视效果,依次交替向左旋转和向右旋转,此时透视的距离是 500px,注意 perspective() 函数和 rotateY() 函数的顺序不能写反:ul li:nth-child(odd) { transform: perspective(500px) rotateY(45deg);}ul li:nth-child(even) { transform: perspective(500px) rotateY(-45deg);}为按钮增加悬停效果,使悬停时的透视距离变短为 200px,透视距离越短,旋转的幅度看起来就越大:ul li:nth-child(odd):hover { transform: perspective(200px) rotateY(45deg); padding-left: 5%;}ul li:nth-child(even):hover { transform: perspective(200px) rotateY(-45deg); padding-right: 5%;}最后,设置一个缓动时间,使效果转换变得平滑:ul li { transition: 0.3s; cursor: pointer;}大功告成! ...

September 29, 2018 · 1 min · jiezi

前端每日实战:146# 视频演示如何用纯 CSS 创作一个脉动 loader

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/wYvGwr可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cnMgQTr源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 10 个子元素:<div class=“loader”> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background: linear-gradient(#eee 70%, pink);}设置容器的样式,是粉色背景并描边的一个圆:.loader { width: 6em; height: 6em; padding: 3em; font-size: 10px; background-color: pink; border-radius: 50%; border: 0.8em solid hotpink;}设置子元素的布局方式为横向平铺:.loader { display: flex; align-items: center; justify-content: space-between;}设置子元素的样式:.loader > span { width: 0.5em; height: 50%; background-color: deeppink;}增加子元素的动画效果:.loader > span { transform: scaleY(0.05) translateX(-0.5em); animation: span-animate 1.5s infinite ease-in-out;}@keyframes span-animate { 0%, 100% { transform: scaleY(0.05) translateX(-0.5em); } 15% { transform: scaleY(1.2) translateX(1em); } 90%, 100% { background-color: hotpink; }}设置子元素下标,让子元素依次播放动画:.loader > span { animation-delay: calc(var(–n) * 0.05s);}.loader > span:nth-child(1) { –n: 1; }.loader > span:nth-child(2) { –n: 2; }.loader > span:nth-child(3) { –n: 3; }.loader > span:nth-child(4) { –n: 4; }.loader > span:nth-child(5) { –n: 5; }.loader > span:nth-child(6) { –n: 6; }.loader > span:nth-child(7) { –n: 7; }.loader > span:nth-child(8) { –n: 8; }.loader > span:nth-child(9) { –n: 9; }.loader > span:nth-child(10) { –n: 10; }增加容器动画,加强脉动的效果:.loader { animation: loader-animate 1.5s infinite ease-in-out;}@keyframes loader-animate { 45%, 55% { transform: scale(1.05); }}大功告成! ...

September 28, 2018 · 1 min · jiezi

前端每日实战:145# 视频演示如何用纯 CSS 创作一个电源开关控件

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/PdMyJd可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/c648Nu7源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,包含 3 个元素,分别代表 input 控件、开关和灯光:<input type=“checkbox” class=“toggle”><div class=“switch”></div><div class=“light”></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #eee;}定义控件的样式,把控件的设置为透明,使其不可见,但仍可与用户交互。其中字号大小是变量,因为 input 控件的字号与正文字号不同,所以需要单独设置:body { font-size: var(–font-size);}:root { –font-size: 16px;}.toggle { position: absolute; font-size: var(–font-size); width: 5em; height: 8em; margin: 0; filter: opacity(0); cursor: pointer; z-index: 2;}设置开关的轮廓:.switch { position: absolute; width: 5em; height: 8em; border-radius: 1.2em; background: linear-gradient(#d2d4d6, white);}用阴影使开关变得立体:.switch { box-shadow: inset 0 -0.2em 0.4em rgba(212, 212, 212, 0.75), inset 0 -0.8em 0 0.1em rgba(156, 156, 156, 0.85), 0 0 0 0.1em rgba(116, 116, 116, 0.8), 0 0.6em 0.6em rgba(41, 41, 41, 0.3), 0 0 0 0.4em #d4d7d8;}用伪元素设置 on 和 off 文本,目前是处于 off 状态:.toggle ~ .switch::before,.toggle ~ .switch::after { position: absolute; width: 100%; text-align: center; font-size: 1.4em; font-family: sans-serif; text-transform: uppercase;}.toggle ~ .switch::before { content: ‘|’; bottom: 1em; color: rgba(0, 0, 0, 0.5); text-shadow: 0 0.1em 0 rgba(255, 255, 255, 0.8);}.toggle ~ .switch::after { content: ‘O’; top: 0.6em; color: rgba(0, 0, 0, 0.45); text-shadow: 0 0.1em 0 rgba(255, 255, 255, 0.4);}把 input 控件设置为 checked状态,以便设置处于 on 状态的样式:<input type=“checkbox” checked=“checked” class=“toggle”>设置处于 on 状态的开关样式:.toggle:checked ~ .switch { background: linear-gradient(#a1a2a3, #f0f0f0); box-shadow: inset 0 0.2em 0.4em rgba(212, 205, 199, 0.75), inset 0 0.8em 0 0.1em rgba(255, 255, 255, 0.77), 0 0 0 0.1em rgba(116, 116, 118, 0.8), 0 -0.2em 0.2em rgba(41, 41, 41, 0.18), 0 0 0 0.4em #d4d7d8;}设置处于 on 状态的文本样式:.toggle:checked ~ .switch::before { bottom: 0.3em; text-shadow: 0 0.1em 0 rgba(255, 255, 255, 0.5);}.toggle:checked ~ .switch::after { top: 1.2em; text-shadow: 0 0.1em 0 rgba(255, 255, 255, 0.15);}接下来设置灯光效果。先设置处于 off 状态的黑暗效果:.toggle ~ .light { width: 100vw; height: 100vh; background-color: #0a0a16; z-index: 1; filter: opacity(0.7);}再设置处于 on 状态的明亮效果:.toggle:checked ~ .light { filter: opacity(0);}大功告成! ...

September 27, 2018 · 2 min · jiezi

前端每日实战:143# 视频演示如何用 CSS 的 Grid 布局创作一枚小松鼠邮票

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/YOoXpv可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/c7KdMt8源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器表示邮票:<div class=“stamp”></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: teal;}设置容器尺寸:.stamp { position: relative; width: 45em; height: 63em; font-size: 6px; padding: 5em; background-color: white;}用重复背景绘制出邮票的齿孔:.stamp { display: flex; flex-direction: column; align-items: center; justify-content: center;}.stamp::after,.stamp::before { content: ‘’; width: 100%; height: 100%; position: absolute; background: radial-gradient(circle, teal 50%, transparent 50%), radial-gradient(circle, teal 50%, transparent 50%); background-size: 3.5em 3.5em;}.stamp::before { top: 1.5em; background-repeat: repeat-y; background-position: -4% 0, 104% 0;}.stamp::after { left: 1.5em; background-repeat: repeat-x; background-position: 0 -3%, 0 103%;}在 html 文件中增加小鸡的 dom 元素,子元素分别表示耳朵、头部、身体、尾巴下部、尾巴上部、腿、爪子:<div class=“stamp”> <div class=“squirrel”> <div class=“ear”></div> <div class=“head”></div> <div class=“body”></div> <div class=“tail-start”></div> <div class=“tail-end”></div> <div class=“leg”></div> <div class=“foot”></div> </div></div>设置 grid 布局的行列尺寸:.squirrel { display: grid; grid-template-columns: 11.5em 7em 15.5em 10.5em; grid-template-rows: 13em 5em 11.5em 22.5em; background-color: silver; padding: 2em; margin-top: -2em;}画出扇形的头部:.head { grid-column: 1; grid-row: 3; background-color: chocolate; border-bottom-left-radius: 100%;}用径向渐变画出眼睛:.head { background-image: radial-gradient( circle at 58% 22%, black 1.4em, transparent 1.4em );}画出扇形的耳朵:.ear { grid-column: 2; grid-row: 2; width: 5em; background-color: bisque; border-bottom-right-radius: 100%;}画出扇形的身体:.body { grid-column: 2 / 4; grid-row: 4; background-color: chocolate; border-top-right-radius: 100%; position: relative; overflow: hidden;}用伪元素,通过阴影画出蜷曲的腿:.body::before { content: ‘’; position: absolute; width: 100%; height: 50%; box-shadow: 2em -2em 4em rgba(0, 0, 0, 0.3); bottom: 0; –w: calc((7em + 15.5em) / 2); border-top-left-radius: var(–w); border-top-right-radius: var(–w);}画出半圆形的小爪子:.foot { grid-column: 1; grid-row: 4; height: 4em; width: 8em; background-color: saddlebrown; justify-self: end; align-self: end; border-radius: 4em 4em 0 0; filter: brightness(0.8);}画出半圆形的尾巴下部:.tail-start { grid-column: 4; grid-row: 4; –h: calc(22.5em - 1.5em); height: var(–h); background-color: bisque; align-self: end; border-radius: 0 var(–h) var(–h) 0;}画出半圆形的尾巴上部:.tail-end { grid-column: 3; grid-row: 1 / 5; –h: calc(13em + 5em + 11.5em + 1.5em); height: var(–h); background-color: chocolate; border-radius: var(–h) 0 0 var(–h);}在 dom 中再增加一些文本,包括标题、作者和面值:<div class=“stamp”> <div class=“puppy”> <!– 略 –> </div> <p class=“text”> <span class=“title”>Squirrel</span> <span class=“author”>comehope</span> <span class=“face-value”>200</span> </p></div>设置标题的文字样式:.text { position: relative; width: calc(100% + 2em * 2); height: 6em; font-family: sans-serif;}.text .title { position: absolute; font-size: 6em; font-weight: bold; color: darkslategray;}设置作者的文字样式:.text .author { position: absolute; font-size: 3em; bottom: -1.2em; color: dimgray;}设置面值的文字样式:.text .face-value { position: absolute; font-size: 14em; right: 0; line-height: 0.9em; color: darkcyan;}大功告成! ...

September 26, 2018 · 2 min · jiezi

前端每日实战:144# 视频演示如何用 D3 和 GSAP 创作一个集体舞动画

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/gdVObN可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/caRLack源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 2 个子容器,.horizontal 代表水平的线段,.vertical 代表垂直的线段,每个子容器中包含 4 个子元素:<div class=“container”> <div class=“horizontal”> <span></span> <span></span> <span></span> <span></span> </div> <div class=“vertical”> <span></span> <span></span> <span></span> <span></span> </div></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: skyblue;}设置容器尺寸,其中 –side-length 是方阵的每一边的元素数量:.container { /* –side-length: 2; */ position: relative; width: calc(40px * calc(var(–side-length))); height: calc(40px * calc(var(–side-length)));}用 grid 布局排列子元素,4 个元素排列成 2 * 2 的方阵:.container .horizontal,.container .vertical { position: absolute; top: 0; left: 0; display: grid; grid-template-columns: repeat(var(–side-length), 1fr);}设置子元素的样式,.horizontal 内的子元素是横条,.vertical 内的子元素是竖条:.container .horizontal span { width: 40px; height: 10px; background: #fff; margin: 15px 0;}.container .vertical span { width: 10px; height: 40px; background: #fff; margin: 0 15px;}至此,静态布局完成,接下来用 d3 批量处理子元素。引入 d3 库:<script src=“https://d3js.org/d3.v5.min.js"></script>删除掉 html 文件中的子元素 dom 节点,删除掉 css 文件中声明的 css 变量。定义方阵每一边的元素数量,并把这个数值赋给 css 变量:const SIDE_LENGTH = 2;let container = d3.select(’.container’) .style(’–side-length’, SIDE_LENGTH);定义一个添加 span 子元素的函数,分别添加横向和竖向的子元素:function appendSpan(selector) { container.select(selector) .selectAll(‘span’) .data(d3.range(SIDE_LENGTH * SIDE_LENGTH)) .enter() .append(‘span’);}appendSpan(’.horizontal’);appendSpan(’.vertical’);此时,布局已改为动态的,可以通过修改 SIDE_LENGTH 的值来创建不同边长的方阵,比如以下语句将创建 5 * 5 的方阵:const SIDE_LENGTH = 5;接下来用 GSAP 创建动画。(注:因 scrimba 在使用 gsap 时会崩溃,所以视频演示采用 css 动画,但 codepen 和 github 均采用 gsap 动画)引入 GSAP 库:<script src=“https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>声明动画变量 animation,声明代表 dom 元素的变量 $horizontalSpan 和 $verticalSpan:let animation = new TimelineMax({repeat: -1});let $horizontalSpan = ‘.container .horizontal span’;let $verticalSpan = ‘.container .vertical span’;先创建横条的动画,共分成 4 步,每个 to 语句的最后一个参数是步骤的名称:animation.to($horizontalSpan, 1, {rotation: 45}, ‘step1’) .to($horizontalSpan, 1, {x: ‘-10px’, y: ‘-10px’}, ‘step2’) .to($horizontalSpan, 1, {rotation: 0, x: ‘0’, y: ‘0’, scaleY: 2, scaleX: 0.5}, ‘step3’) .to($horizontalSpan, 1, {rotation: 90, scaleY: 1, scaleX: 1}, ‘step4’)再创建竖条的动画,to 语句的步骤名称与横条的步骤名称相同,以便与横条保持动画同步:animation.to($verticalSpan, 1, {rotation: 45}, ‘step1’) .to($verticalSpan, 1, {x: ‘10px’, y: ‘10px’}, ‘step2’) .to($verticalSpan, 1, {x: ‘0’, y: ‘0’, scaleX: 2, scaleY: 0.5}, ‘step3’) .to($verticalSpan, 1, {rotation: 90, scaleX: 1, scaleY: 1}, ‘step4’);在动画的末尾用时间尺度缩放函数让动画播放速度加快一倍:animation.timeScale(2);最后,把方阵的边长改为 10,方阵越大就越有气势:const SIDE_LENGTH = 10;大功告成! ...

September 26, 2018 · 2 min · jiezi

前端每日实战:141# 视频演示如何用 CSS 的 Grid 布局创作一枚小狗邮票

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/BOeEYV可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cPQ3vcq源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器表示邮票:<div class=“stamp”></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: teal;}设置容器尺寸:.stamp { position: relative; width: 40.5em; height: 71em; font-size: 6px; padding: 5em; background-color: white;}用重复背景绘制出邮票的齿孔:.stamp { display: flex; flex-direction: column; align-items: center; justify-content: center;}.stamp::after,.stamp::before { content: ‘’; width: 100%; height: 100%; position: absolute; background: radial-gradient(circle, teal 50%, transparent 50%), radial-gradient(circle, teal 50%, transparent 50%); background-size: 3.5em 3.5em;}.stamp::before { top: 1.5em; background-repeat: repeat-y; background-position: -4.5% 0, 104.5% 0;}.stamp::after { left: 1.5em; background-repeat: repeat-x; background-position: 0 -2.5%, 0 102.5%;}在 html 文件中增加小狗的 dom 元素,子元素分别表示耳朵、头部、眼睛、舌头、身体、尾巴和爪子:<div class=“stamp”> <div class=“puppy”> <span class=“ear”></span> <span class=“head”></span> <span class=“eyes”></span> <span class=“tongue”></span> <span class=“body”></span> <span class=“tail”></span> <span class=“foot”></span> </div></div>设置 grid 布局的行列尺寸:.puppy { display: grid; grid-template-columns: 10em 22.5em 8em; grid-template-rows: 21em 12.5em 3.75em 22.5em; background-color: tan; padding: 2em; margin-top: -1em;}画出小狗的头部,跨第1列和第2列、第2行和第3行,是一个半圆形:.head { grid-column: 1 / 3; grid-row: 2 / 4; border-bottom-left-radius: calc(12.5em + 3.75em); border-bottom-right-radius: calc(12.5em + 3.75em); background-color: bisque;}用伪元素画出鼻子,是一个扇形,多余的部分被隐藏了:.head { position: relative; overflow: hidden;}.head::before { content: ‘’; position: absolute; width: 7em; height: 7em; border-bottom-right-radius: 100%; background-color: sienna;}画出半圆形的眼晕:.eyes { grid-column: 2; grid-row: 2; justify-self: end; position: relative; height: 10.5em; width: 21em; border-radius: 0 0 10.5em 10.5em; background-color: sienna;}用径向渐变画出眼珠:.eyes { background-image: radial-gradient( circle at 37% 33%, black 1.4em, transparent 1.4em );}画出半圆形的耳朵:.ear { grid-column: 2; grid-row: 1; justify-self: end; width: 10.5em; border-radius: 21em 0 0 21em; background-color: sienna;}画出扇形的舌头:.tongue { grid-column: 1; grid-row: 3; width: 5.5em; height: 5.5em; background-color: indianred; border-bottom-left-radius: 100%;}画出扇形的身体:.body { grid-column: 2; grid-row: 4; background-color: sienna; border-top-left-radius: 100%;}用伪元素,通过阴影画出中蹲着的腿:.body { position: relative; overflow: hidden;}.body::after { content: ‘’; position: absolute; height: 50%; width: 100%; border-radius: 11.25em 11.25em 0 0; box-shadow: 2em 0 4em rgba(0, 0, 0, 0.3); bottom: 0;}画出半圆形的尾巴:.tail { grid-column: 1; grid-row: 4; justify-self: end; align-self: end; height: 17.5em; width: 8.75em; background-color: bisque; border-radius: 17.5em 0 0 17.5em;}画出半圆形的小爪子:.foot { grid-column: 3; grid-row: 4; align-self: end; height: 4em; background-color: bisque; border-radius: 4em 4em 0 0;}在 dom 中再增加一些文本,包括标题、作者和面值:<div class=“stamp”> <div class=“puppy”> <!– 略 –> </div> <p class=“text”> <span class=“title”>Puppy</span> <span class=“author”>comehope</span> <span class=“face-value”>80</span> </p></div>设置标题的文字样式:.text { position: relative; width: calc(100% + 2em * 2); height: 6em; font-family: sans-serif;}.text .title { position: absolute; font-size: 6em; font-weight: bold; color: sienna;}设置作者的文字样式:.text .author { position: absolute; font-size: 3em; bottom: -1.2em; color: dimgray;}设置面值的文字样式:.text .face-value { position: absolute; font-size: 14em; right: 0; line-height: 0.9em; color: darkcyan;}大功告成! ...

September 25, 2018 · 2 min · jiezi

前端每日实战:142# 视频演示如何用 CSS 的 Grid 布局创作一张小鸡邮票

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/mGZbmQ可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cWMPaha源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器表示邮票:<div class=“stamp”></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: teal;}设置容器尺寸:.stamp { position: relative; width: 57em; height: 71em; font-size: 5px; padding: 5em; background-color: white;}用重复背景绘制出邮票的齿孔:.stamp { display: flex; flex-direction: column; align-items: center; justify-content: center;}.stamp::after,.stamp::before { content: ‘’; width: 100%; height: 100%; position: absolute; background: radial-gradient(circle, teal 50%, transparent 50%), radial-gradient(circle, teal 50%, transparent 50%); background-size: 3.5em 3.5em;}.stamp::before { top: 1.5em; background-repeat: repeat-y; background-position: -3% 0, 103% 0;}.stamp::after { left: 1.5em; background-repeat: repeat-x; background-position: 0 -2.5%, 0 102.5%;}在 html 文件中增加小鸡的 dom 元素,子元素分别表示头部、喙、身体、尾巴、腿、爪子、太阳、桔子:<div class=“stamp”> <div class=“rooster”> <span class=“head”></span> <span class=“beak”></span> <span class=“body”></span> <span class=“tail”></span> <span class=“leg”></span> <span class=“foot”></span> <span class=“sun”></span> <span class=“orange-stuff”></span> </div></div>设置 grid 布局的行列尺寸:.rooster { display: grid; grid-template-columns: 22.5em 13em 1.75em 14.5em 4.5em; grid-template-rows: 12.5em 14.5em 15em 8em 5.5em; background-color: wheat; padding: 2em; margin-top: -2em;}画出扇形的头部:.head { grid-column: 4; grid-row: 2; background-color: burlywood; border-top-left-radius: 100%;}画出小鸡的眼睛和脸上的红晕:.head { position: relative;}.head::after { content: ‘’; position: absolute; width: 2.8em; height: 2.8em; border-radius: 50%; background-color: black; right: 30%; box-shadow: 2em 4em 4em rgba(255, 100, 0, 0.5);}画出扇形的喙:.beak { grid-column: 5; grid-row: 2; height: 4.5em; background-color: darkorange; border-bottom-right-radius: 100%;}画出半圆形的身体:.body { grid-column: 2 / 5; grid-row: 3; width: 30em; background-color: saddlebrown; border-radius: 0 0 15em 15em;}用伪元素,通过阴影画出翅膀:.body { position: relative; overflow: hidden;}.body::after { content: ‘’; position: absolute; width: 20em; height: 10em; border-radius: inherit; box-shadow: 4em 2em 4em rgba(0, 0, 0, 0.3); left: calc((30em - 20em) / 2);}画出扇形的尾巴:.tail { grid-column: 1; grid-row: 1 / 3; height: 22.5em; background-color: burlywood; align-self: end; border-top-left-radius: 100%;}画出扇形的腿:.leg { grid-column: 4; grid-row: 4; width: 8em; background-color: burlywood; border-bottom-right-radius: 100%;}画出扇形的小爪子:.foot { grid-column: 4; grid-row: 5; width: 5.5em; background-color: darkorange; border-top-right-radius: 100%;}画出半圆形的太阳:.sun { grid-column: 3 / 5; grid-row: 1; width: 17em; –h: calc(17em / 2); height: var(–h); background-color: darkorange; border-radius: 0 0 var(–h) var(–h);}画出圆形的桔子和半圆形的叶片,注意此处叶片的画法与前面画半圆形的画法不同:.orange-stuff { grid-column: 1; grid-row: 3 / 6; width: 16em; height: 16em; background-color: darkorange; align-self: end; justify-self: end; border-radius: 50%; position: relative;}.orange-stuff::before { content: ‘’; position: absolute; width: 8em; height: 8em; background: linear-gradient(45deg, transparent 50%, saddlebrown 50%); border-radius: 50%; top: -6.8em; left: 10%;}在 dom 中再增加一些文本,包括标题、作者和面值:<div class=“stamp”> <div class=“puppy”> <!– 略 –> </div> <p class=“text”> <span class=“title”>Rooster</span> <span class=“author”>comehope</span> <span class=“face-value”>120</span> </p></div>设置标题的文字样式:.text { position: relative; width: calc(100% + 2em * 2); height: 6em; font-family: sans-serif;}.text .title { position: absolute; font-size: 6em; font-weight: bold; color: brown;}设置作者的文字样式:.text .author { position: absolute; font-size: 3em; bottom: -1.2em; color: dimgray;}设置面值的文字样式:.text .face-value { position: absolute; font-size: 14em; right: 0; line-height: 0.9em; color: darkcyan;}大功告成! ...

September 25, 2018 · 2 min · jiezi

前端每日实战:139# 视频演示如何用 CSS 和 D3 创作光斑粒子交相辉映的动画

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/zJybdq可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cGV7phy源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 3 个子元素:<div class=‘container’> <span></span> <span></span> <span></span></div>设置页面背景:body { margin: 0; width: 100vw; height: 100vh; background: radial-gradient(circle at center, #222, black 20%);}定义容器尺寸:.container { width: 100%; height: 100%;}设置光斑的样式,其中定义了偏亮和偏暗的 2 个颜色变量:.container { position: relative;}.container span { –bright-color: #d4ff00; –dark-color: #e1ff4d; position: absolute; width: 30px; height: 30px; margin-left: -15px; margin-top: -15px; background: radial-gradient(var(–bright-color), var(–dark-color)); border-radius: 50%; box-shadow: 0 0 25px 3px var(–dark-color);}把光斑定位到页面中心:.container span { transform: translateX(50vw) translateY(50vh);}增加光斑从中心向四周扩散和收缩的动画效果:.container span { animation: animate 1.5s infinite alternate; animation-delay: calc(var(–n) * 0.015s);}@keyframes animate { 80% { filter: opacity(1); } 100% { transform: translateX(calc(var(–x) * 1vw)) translateY(calc(var(–y) * 1vh)); filter: opacity(0); }}定义动画中用到的变量 –x、–y 和 –n:.container span:nth-child(1) { –x: 20; –y: 30; –n: 1; }.container span:nth-child(2) { –x: 60; –y: 80; –n: 2;}.container span:nth-child(3) { –x: 10; –y: 90; –n: 3;}设置容器的景深,使光斑的运动有从远到近的感觉:.container { perspective: 500px;}.container span { transform: translateX(50vw) translateY(50vh) translateZ(-1000px);}至此,少量元素的动画效果完成,接下来用 d3 批量创建 dom 元素和 css 变量。引入 d3 库,同时删除 html 文件中的子元素和 css 文件中的子元素变量:<script src=“https://d3js.org/d3.v5.min.js"></script>定义光斑粒子数量:const COUNT = 3;批量创建 dom 元素:d3.select(’.container’) .selectAll(‘span’) .data(d3.range(COUNT)) .enter() .append(‘span’);为 dom 元素设置 –x、–y 和 –n 的值,其中 –x 和 –y 是 1 到 99 的随机数:d3.select(’.container’) /* 略 / .style(’–x’, () => d3.randomUniform(1, 99)()) .style(’–y’, () => d3.randomUniform(1, 99)()) .style(’–n’, d => d);再为 dom 元素设置 –bright-color 和 –dark-color 的值:d3.select(’.container’) / 略 */ .style(’–dark-color’, (d) => d3.color(hsl(${70 + d * 0.1}, 100%, 50%))) .style(’–bright-color’, (d) => d3.color(hsl(${70 + d * 0.1}, 100%, 50%)).brighter(0.15));最后,把光斑粒子数量设置为 200 个:const COUNT = 200;大功告成! ...

September 20, 2018 · 2 min · jiezi