CSS开发技巧——行为技巧
-
使用overflow-scrolling支持弹性滚动
iOS页面
非body元素
的滚动操作会非常卡(Android不会出现此情况),通过overflow-scrolling:touch
调用Safari原生滚动来支持弹性滚动,增加页面滚动的流畅度- 场景:iOS页面滚动
-
使用transform启动GPU硬件加速
有时执行动画可能会导致页面卡顿,可在特定元素中使用硬件加速来避免这个问题
- 场景:动画元素(绝对定位、同级中超过6个以上使用动画)
-
使用attr()抓取data-*
在标签上自定义属性
data-*
,通过attr()
获取其内容赋值到content
上-
场景:提示框
-
<div class="bruce flex-ct-y" data-title="使用attr()抓取节点属性"> <a class="hover-tips btn-1" href="https://www.baidu.com" data-msg="Hello World">提示框</a> <a class="hover-tips btn-2" href="https://www.baidu.com"></a> </div> <style> .hover-tips { position: relative; padding: 0 20px; border-radius: 10px; height: 40px; background-color: #66f; line-height: 40px; color: #fff; & + .hover-tips { margin-top: 10px; } &.btn-1 { &::after { position: absolute; left: 0; top: 0; border-radius: 5px; width: 100%; height: 100%; background-color: rgba(#000, .5); opacity: 0; text-align: center; font-size: 12px; content: attr(data-msg); transition: all 300ms; } &:hover::after { left: calc(100% + 20px); opacity: 1; } } &.btn-2:empty::after { content: attr(href); } } </style>
-
-
使用:valid和:invalid校验表单
``使用伪类
:valid
和:invalid
配合pattern
校验表单输入的内容- 场景:表单校验
-
使用pointer-events禁用事件触发
通过
pointer-events:none
禁用事件触发(默认事件、冒泡事件、鼠标事件、键盘事件等),相当于``的disabled
-
场景:限时点击按钮(发送验证码倒计时)、事件冒泡禁用(多个元素重叠且自带事件、a标签跳转)
-
<div class="bruce flex-ct-x" data-title="使用pointer-events禁用事件触发"> <a class="disabled-trigger" href="https://www.baidu.com">点我</a> </div> <style> .disabled-trigger { padding: 0 20px; border-radius: 10px; height: 40px; background-color: #66f; pointer-events: none; line-height: 40px; color: #fff; } </style>
-
-
使用+或~美化选项框
``使用
+
或~
配合for
绑定radio
或checkbox
的选择行为-
场景:选项框美化、选中项增加选中样式
-
<div class="bruce flex-ct-x" data-title="使用+或~美化选项表单"> <ul class="beauty-selection"> <li> <input id="fed-engineer" type="radio" name="radioName" hidden> <label for="fed-engineer"></label> <span>前端工程师</span> </li> <li> <input id="bed-engineer" type="radio" name="radioName" hidden> <label for="bed-engineer"></label> <span>后端工程师</span> </li> <li> <input id="fsd-engineer" type="radio" name="radioName" hidden> <label for="fsd-engineer"></label> <span>全栈工程师</span> </li> </ul> </div> <style> .beauty-selection { display: flex; li { display: flex; align-items: center; & + li { margin-left: 20px; } } input:checked + label { background-color: #f90; } label { margin-right: 5px; padding: 2px; border: 1px solid #f90; border-radius: 100%; width: 18px; height: 18px; background-clip: content-box; cursor: pointer; transition: all 300ms; &:hover { border-color: #09f; background-color: #09f; box-shadow: 0 0 7px #09f; } } span { font-size: 16px; } } </style>
-
-
使用:focus-within分发冒泡响应
表单控件触发
focus
和blur
事件后往父元素进行冒泡,在父元素上通过:focus-within
捕获该冒泡事件来设置样式-
<div class="bruce flex-ct-x" data-title="使用:focus-within分发冒泡响应"> <form class="bubble-distribution"> <h3>注册</h3> <div class="accout"> <input type="text" placeholder="请输入手机或邮箱" pattern="^1[3456789]\d{9}$|^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$" required> <img src="https://b-gold-cdn.xitu.io/v3/static/img/greeting.1415c1c.png"> </div> <div class="password"> <input type="password" placeholder="请输入密码(6到20位字符)" pattern="^[\dA-Za-z_]{6,20}$" required> <img src="https://b-gold-cdn.xitu.io/v3/static/img/blindfold.58ce423.png"> </div> <div class="code"> <input type="text" placeholder="请输入邀请码(6位数字)" pattern="^[\d]{6}$" maxLength="6" required> <button type="button">查询</button> <img src="https://b-gold-cdn.xitu.io/v3/static/img/greeting.1415c1c.png"> </div> <img src="https://b-gold-cdn.xitu.io/v3/static/img/normal.0447fe9.png"> <ul> <li> <input id="male" type="radio" name="sex"> <label for="male">Boy</label> </li> <li> <input id="female" type="radio" name="sex"> <label for="female">Girl</label> </li> </ul> <button type="button">注册</button> </form> </div> <style> .bruce { background-color: #999; } .bubble-distribution { position: relative; margin-top: 50px; padding: 25px; border-radius: 2px; width: 320px; background-color: #fff; h3 { font-size: 16px; color: #333; } div { margin-top: 10px; } img { position: absolute; left: 50%; bottom: 100%; margin: 0 0 -20px -60px; width: 120px; } ul { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; height: 30px; line-height: 30px; } li { position: relative; width: 45%; transition: all 300ms; &:focus-within { background: linear-gradient(90deg, #09f 50%, transparent 0) repeat-x, linear-gradient(90deg, #09f 50%, transparent 0) repeat-x, linear-gradient(0deg, #09f 50%, transparent 0) repeat-y, linear-gradient(0deg, #09f 50%, transparent 0) repeat-y; background-position: 0 0, 0 100%, 0 0, 100% 0; background-size: 8px 1px, 8px 1px, 1px 8px, 1px 8px; animation: move 500ms infinite linear; } } input[type=text], input[type=password] { padding: 10px; border: 1px solid #e9e9e9; border-radius: 2px; width: 100%; height: 40px; outline: none; transition: all 300ms; &:focus:valid { border-color: #09f; } &:focus:invalid { border-color: #f66; } } input[type=radio] { position: absolute; width: 0; height: 0; &:checked + label { border: 3px solid transparent; background-color: #09f; color: #fff; } } label { display: block; border-bottom: 1px solid #ccc; width: 100%; background-clip: padding-box; cursor: pointer; text-align: center; transition: all 300ms; } button { margin-top: 10px; border: none; border-radius: 2px; width: 100%; height: 40px; outline: none; background-color: #09f; cursor: pointer; color: #fff; transition: all 300ms; } .accout, .password, .code { img { display: none; margin-bottom: -27px; } &:focus-within { img { display: block; } & ~ img { display: none; } } } .code { display: flex; justify-content: space-between; button { margin-top: 0; } input { &:not(:placeholder-shown) { width: 70%; & + button { width: 25%; } } &:placeholder-shown { width: 100%; & + button { width: 0; opacity: 0; } } } } } @keyframes move { to { background-position: 6% 0, -6% 100%, 0 -6%, 100% 6%; } } </style>
-
使用:hover描绘鼠标跟随
将整个页面等比划分成小的单元格,每个单元格监听
:hover
,通过:hover
触发单元格的样式变化来描绘鼠标运动轨迹-
.bruce(data-title="使用:hover描绘鼠标跟随") ul.mouse-following - for (var i = 0; i < 500; i++) li <style> @function random-num($max, $min: 0, $u: 1) { @return ($min + random($max)) * $u; } .mouse-following { display: flex; overflow: hidden; flex-wrap: wrap; height: 100%; cursor: pointer; li { position: relative; width: 30px; height: 30px; &::before { position: absolute; left: 0; right: 0; top: 0; bottom: 0; border-radius: 100%; background-color: transparent; content: ""; transform: scale3d(.1, .1, 1); transition: all 500ms ease-in; } &:hover { &::before { transform: scale3d(1.8, 1.8, 1.8); transition: transform 0s; } } @for $i from 1 through 500 { &:nth-child(#{$i}):hover { &::before { background-color: rgba(random-num(255), random-num(255), random-num(255), .8); } } } } } </style>
-
使用max-height切换自动高度
通过
max-height
定义收起的最小高度和展开的最大高度,设置两者间的过渡切换-
场景:隐藏式子导航栏、悬浮式折叠面板
-
<div class="bruce flex-ct-x" data-title="使用max-height切换自动高度"> <ul class="auto-height"> <li> <h3>列表1</h3> <p>内容1<br>内容2<br>内容3<br>内容4</p> </li> <li> <h3>列表2</h3> <p>内容1<br>内容2<br>内容3<br>内容4</p> </li> <li> <h3>列表3</h3> <p>内容1<br>内容2<br>内容3<br>内容4</p> </li> </ul> </div> <style> .auto-height { width: 300px; li { cursor: pointer; & + li { margin-top: 5px; } &:hover p { border-bottom-width: 1px; max-height: 600px; } } h3 { padding: 0 20px; height: 40px; background-color: #f66; cursor: pointer; line-height: 40px; font-size: 16px; color: #fff; } p { overflow: hidden; padding: 0 20px; border: 1px solid #f66; border-top: none; border-bottom-width: 0; max-height: 0; line-height: 30px; transition: all 500ms; } } </style>
-
-
使用transform模拟视差滚动
通过
background-attachment:fixed
或transform
让多层背景以不同的速度移动,形成立体的运动效果-
<div class="bruce" data-title="使用transform模拟视差滚动"> <ul class="parallax-scrolling"> <li>translateZ(-1px)</li> <li>translateZ(-2px)</li> <li>translateZ(-3px)</li> </ul> <p>内容</p> <ul class="parallax-scrolling"> <li>translateZ(-1px)</li> <li>translateZ(-2px)</li> <li>translateZ(-3px)</li> </ul> </div> <style> $bg: "https://static.yangzw.vip/codepen/lake.jpg"; .bruce { overflow-x: hidden; overflow-y: auto; perspective: 1px; transform-style: preserve-3d; p { height: 300px; line-height: 300px; text-align: center; font-size: 20px; color: #f66; } } .parallax-scrolling { display: flex; justify-content: center; align-items: center; height: 1000px; background: url($bg) no-repeat center fixed; li { width: 500px; text-align: center; font-weight: bold; font-size: 60px; &:nth-child(1) { color: #f66; transform: translateZ(-1px); } &:nth-child(2) { color: #09f; transform: translateZ(-2px); } &:nth-child(3) { color: #3c9; transform: translateZ(-3px); } } } </style>
-
使用animation-delay保留动画起始帧
通过
transform-delay
或animation-delay
设置负值时延保留动画起始帧,让动画进入页面不用等待即可运行-
场景:开场动画
-
<div class="bruce flex-ct-x" data-title="使用animation-delay保留动画首帧"> <ul class="initial-keyframe"> <li></li> <li></li> <li></li> </ul> </div> <style> .initial-keyframe { position: relative; width: 100px; height: 100px; li { position: absolute; border-radius: 100%; width: 100%; height: 100%; background-color: #3c9; transform: rotate(0) translate(-80px, 0); animation: rotate 3s linear infinite; &:nth-child(2) { animation-delay: -1s; } &:nth-child(3) { animation-delay: -2s; } } } @keyframes rotate { to { transform: rotate(1turn) translate(-80px, 0); } } </style>
-
-
使用resize拉伸分栏
通过
resize
设置横向自由拉伸来调整目标元素的宽度-
场景:富文本编辑器、分栏阅读
-
<div class="bruce flex-ct-x" data-title="使用resize拉伸多列分栏"> <div class="stretching-column"> <div class="left"> <div class="resize-bar"></div> <div class="resize-line"></div> <div class="resize-text">ABCDEFGHIJKLMNOPQRSTUVWXYZ</div> </div> <div class="right">ABCDEFGHIJKLMNOPQRSTUVWXYZ</div> </div> </div> <style> .stretching-column { overflow: hidden; border: 1px solid #09f; width: 600px; height: 300px; line-height: 20px; font-size: 16px; color: #f90; .left { overflow: hidden; float: left; position: relative; height: 100%; } .right { overflow: hidden; padding: 10px; height: 100%; background-color: #f0f0f0; word-break: break-all; } .resize-bar { overflow: scroll; width: 200px; height: 100%; opacity: 0; resize: horizontal; &::-webkit-scrollbar { width: 200px; height: 100%; } &:hover, &:active { & ~ .resize-line { border-left: 1px dashed #09f; } } } .resize-line { position: absolute; right: 0; top: 0; bottom: 0; border-left: 1px solid #ccc; border-right: 2px solid #f0f0f0; pointer-events: none; } .resize-text { overflow-x: hidden; position: absolute; left: 0; right: 5px; top: 0; bottom: 0; padding: 10px; word-break: break-all; } } </style>
-