某著名小白说过 :世上原本处处都是坑,只要走的人多了,也就把坑都给埋了。该小白还说过:坑自己并不可怕,可怕的是踩了一次以后,还第2、第三次踩到了相同的坑。html
所谓"坑",主要是因为咱们对某些知识点理解不够透彻,致使在应用的时出现了一些奇怪的问题。由于咱们每一个人,对于某个知识点的理解程度不同,因此,有些坑我以为真的很坑,可是你可能以为一点都不坑,由于你早就对它了如指掌了。前端
这里列举的一些坑,都是我过去一年在项目中所遇到过的,并当时在笔记中记录下来的,如今稍加整理就造成了这篇博客,以供往后查阅。git
不知不觉,开头又bb了这么多,仍是赶忙进入正题哈。github
以前作炉石盒子的天梯环境页面,地址是 炉石天梯环境 ,就在项目作得差很少的时候,准备上线了, QA 忽然发现了以下的一个 bug:
web
有一个选择排序方式的下拉菜单,它的定位是 position: absolute
,正常来讲,它应该会覆盖在其余元素之上的,但是为何 0.14%
反而会覆盖在它上面呢? 在代码中找了很久,那个 0.14%
并无设置 z-index
属性,也没有 position: absolute
这样的东西,真是好郁闷哦。后来到 mdn 查文档才发现,原来是 opacity
属性引发 的: opacity 属性值小于 1 的元素会建立新的层叠上下文 。由于当时我有个偷懒的作法,字体继承的颜色是 #666
, 我想让 0.14%
(天梯比率)颜色变浅一些,直接加了个 opacity: 0.6
,致使了建立了新的层叠上下文,层级比下拉菜单高了,因此就覆盖在了上面。具体什么是层叠上下文,以及哪些属性会建立新的层叠上下文,这里也不介绍了有须要的能够参考一下 层叠上下文canvas
虽然上面描述得已经很详细了,可是可能因为个人表达能力不太好,有些朋友还不是很明白个人意思,能够看一下这里的 demo 代码:小程序
<div class="menu"> <div class="title">下拉菜单</div> <div class="menu-list"> <div class="item">菜单1</div> <div class="item">菜单2</div> <div class="item">菜单3</div> </div> </div> <div class="content"> 我是半透明的文字,能够覆盖在下拉菜单之上哦~ </div> <style> .menu { position: relative; } .menu-list { display: none; position: absolute; background: #ccc; } .menu:hover .menu-list { display: block; } .content { opacity: 0.6; } </style>
将鼠标移动到下拉菜单上,就会发现文字会发生重叠了:
微信小程序
那这个坑有什么解决办法呢?最简单的就是下拉菜单添加个属性 z-index: 1
。另外,这里再啰嗦一下,就是z-index
的值不要乱设置。之前刚刚接触前端时,会常常看一些视频教程,看到里面讲师动不动就设置个 z-index: 999
之类的特别大的数值。这是一个很差的习惯。张鑫旭老师在《CSS世界》一书中,提到了 不三原则
,就是说通常状况下,z-index
的值不要超过3,基本能知足大多数的需求了。数组
以前作漫画阅读器,由于漫画可能有长图片,也可能有短图片。长图片能够滚动查看,短图片就居中显示。因此,很天然会想到用 flex 布局来实现。简单的代码以下:微信
<div class="app"> <img src="https://m.tuniucdn.com/fb2/t1/G1/M00/F1/51/Cii9EFkAaZ-IRgGNAATB18ldk0UAAJzuQN-p1cABMHv15.jpeg" alt=""> </div> <style> html, body { height: 100%; } .app { display: flex; height: 100%; justify-content: center; align-items: center; } img { width: 100%; } </style>
这里,咱们的 .app
容器里面这里有一张很长的图片。当咱们运行上面的代码,若是你仔细观察原图和页面显示的图片,就会发现图片的顶部和底部的一些内容看不到了,滚动条到了必定位置就没法滚动了。正常来讲,咱们应该能够经过滚动条的上下滑动看到图片的所有内容才对的。当时我想了好久也没有想出来缘由,最后到 stackoverflow 找到了答案 Can't scroll to top of flex item that is overflowing container
答案中有提到,能够设置子项的 margin: auto
来实现内容溢出时也自动居中(包括水平和垂直的):
修改后的 CSS 代码以下:
.app { display: flex; height: 100%; } img { width: 100%; margin: auto; }
因此,之后若是在使用 flex 布局实现居中,若是子项的内容会溢出 flex 容器 ,能够将子项设置为 margin: auto
试试。
CSS3 的 transform 属性也算是比较经常使用的,特别是作一些动画效果的时候,用它来移动元素的位置,性能会比设置 top 或 left 要高一些。可是,若是一个元素设置了 transform 属性,而它的子元素又设置 fixed 定位,那么这个 fixed 定位的子元素表现会有些奇怪,以下代码:
<div class="app"> <button onclick="layer.style.display='block'">弹出蒙层</button> <div class="layer" id="layer"></div> </div> <style> .app { position: relative; width: 100px; height: 100px; background: #ccc; /* 使用transform让元素向下偏移20px */ transform: translate(0, 20px); } .layer { display: none; position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: rgba(0, 0, 0, 0.7); } </style>
打开页面,效果是这样的:
咱们但愿点击“弹出蒙层”按钮后,就显示个覆盖整个窗口的蒙层。可是结果却出乎意料。以下:
蒙层只是遮住了小正方形,这不是咱们想要的结果,由于咱们知道,fixed 定位是相对于屏幕视口(viewport)定位的, 可是,本例却相对于它的父亲元素。这是为何呢?若是认真查阅 mdn文档 ,就会找到答案:
可见,问题的缘由在于,咱们只是记住了fixed是相对于 viewport 定位,可是也有特殊状况: 当元素祖先的 transform 属性非 none 时,容器由视口改成该祖先 。因此,这并非bug,是由于我基础不扎实致使的。事实上, 除了 transform 会改变 fixed 的定位元素以外,还有其余属性也会改变,ChokCoco大佬有一篇文章作了详细的讲解,想要了解更多的请点击 不受控制的 position:fixed
那遇到这种状况怎么办呢?比较好的办法就是把 fixed 元素移到外面去,不要放到有 transform 属性的元素里面。可是,有时候咱们没有办法移到外面怎么办呢?好比,这是它是一个子组件,它的某个父亲组件就是用了 transform,那怎么办呢?我也不知道怎么办,欢迎你们探讨一下哈哈哈~
fixed 定位还具备其余的坑,这里也不展开了,有兴趣的可看 看github 上有大佬整理好的这篇文章 移动端web页面使用position:fixed问题总结
咱们都知道, video 标签设置了 playsinline 就能够内联播放视频,而不是全屏播放。(注意:前提是客户端的 Webview 配置了容许内联播放,因此有时候虽然设置了 playsinline,但在某些 app 里面打开依然是全屏播放,这不是前端的锅哦)。最近有一个需求,相似下面这样的:
页面上有一个视频,视频播下面有一个按钮,点击按钮就弹出一个图片,该图片要覆盖整个屏幕,好比是这样的:
示例代码以下:
<video id="video" controls="" playsinline="" src="https://vod.cc.163.com/file/5bcbe1ae9efdc0608bb6d06b.mp4"></video> <img id="image" src="https://ds.163.com/2018/mrzh/appointment/static/img/bg-body.cdef1ec.jpg" alt=""> <button id="button">弹出图片</button> <style> video, img { width: 100%; } img { display: none; position: absolute; top: 0; } </style> <script> var video = document.getElementById('video'); var image = document.getElementById('image'); var button = document.getElementById('button'); button.onclick = function() { image.style.display='block'; } image.onclick = function() { this.style.display='none'; } </script>
可是,在安卓上却发现一个问题,开始播放视频后(注意,只有播放视频后才能够复现),点击“弹出图片”按钮,显示以下所示:
图片没法覆盖在视频播放器上面。而后,我设置了 z-index 或者 transform ,都没有任何效果。最后, 剩下的可能缘由就是: 安卓微信视频播放器实际上用的是原生组件。为了验证这一猜测,咱们能够启用开发者选项的绘图模式 (开发者选项 --> 绘图 --> 显示布局边界,不一样机型不同,找不到的请百度找一下哈),结果以下:
看到没有,视频是一个完整的有边框的东西,证实他是一个独立于 Webview 的原生组件。
那怎么办呢?只能上网找答案呀!咱们都知道,微信 webview 使用的是 X5 内核,因此我也但愿能从它的开发者文档上找到一些有用的信息,好不容易找到了一篇叫作 H5同层播放器接入规范 。它说能够能够在 video 标签添加一个属性 x5-video-player-type ,而且给出的例子是这样的:
<video src="http://xxx.mp4" x5-video-player-type="h5"/>
我当时很高兴,觉得问题就这样解决了,然并卵,添加了 x5-video-layer-type 属性以后,playsinlie 属性就失效了,没法内联播放了,只能全屏播放,因此,不能添加这个属性。
而后我就想,既然没法覆盖这个视频,那在弹出图片的时候能不能把视频给隐藏掉?而后关闭图片的时候再把视频显示回来呢?因而就把 JS 代码改为下面这样:
button.onclick = function() { image.style.display='block'; video.style.display = 'none'; } image.onclick = function() { this.style.display='none'; video.style.display = 'block'; }
而后,这样就能够了。由于我在网上找不到更好的办法,若是你们遇到这个问题能够参考这种作法。固然,若是大家找到了有更好的办法,欢迎评论分享出来哈~
关于安卓微信视频播放器的坑就先讲到这里啦。
等等,一讲到原生组件,这里还得再补充一下微信小程序相关的东西,固然,我本身尚未太小程序的开发的经验, 这是以前的一次内部交流会,一位同事的分享:小程序在渲染的时候,大多数组件都是渲染成 HTML 组件,可是有少部分好比 canvas、 video、 input、 map 等会渲染成原生组件的。因此,若是你在写小程序时,想用一段文字覆盖在一个 canvas 上,发现怎么设置都没法实现,那是由于 canvas 渲染后是原生组件,而文字是 html 组件,因此没法覆盖上去的 。那有什么办法呢?能够考虑把文字放到 cover-view 上, 它也是一种原生组件,能够覆盖在 canvas 上的。具体的能够参考小程序官方文档 原生组件说明
关于2018踩的坑就写到这里了,固然还有一些其余的,暂时没有时间整理,下次若是整理后,再写一篇补充一下。
若是你们有什么问题,或者过去踩到过了哪些坑,欢迎在评论区讨论哈。