w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com zh-hans w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-model.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-event-intro.html">通过上一节的学习</a>,对DOM事件有了一个简单的了解。但这只是学习DOM事件相关知识的起步点。今天来了解一下DOM事件的模型。</p> <h2>基本事件模型</h2> <p>在Web应用程序或Web网站中,可以通过使用者操作或系统的事件,达到相应的响应。而在JavaScript中,事件在未得到标准化之前,各浏览器就有一个事件模型 —— <strong>基本事件模型(Basic Event Model)</strong>。</p> <p>在基本事件模型中,要在某个事件发生时,调用指定的函数,也就是上一节中介绍的<strong>事件处理程序</strong>。这个程序会指定事件触发将会做什么样的事情。打个比方,当Web页面加载完所有资源之后,即<code>window</code>的<code>load</code>事件中做指定的事情:</p> <pre><code>window.onload = function () { // window的load事件发生时要做的事情... } </code></pre> <p>除此之外,事件还可以由使用者的操作一些事情来触发事件。比如在按钮上绑定一个<code>click</code>事件:</p> <pre><code>&lt;!-- HTML --&gt; &lt;button&gt;Click Me!&lt;/button&gt; // Script let handler = function () { console.log(this) } document.querySelector('button').onclick = handler </code></pre> <p>上面的代码,当用户用鼠标点击按钮时会调用<code>handler()</code>函数,打印出来的<code>this</code>就是用户点击的按钮。像这样的做法,被称为<strong>传统模型(Traditional Model)</strong>或<strong>传统注册模型(Traditional Registration Model)</strong>。这种事件模型也被称为<strong>DOM0级模型</strong>。</p> <p>基本事件模型有一个典型的缺点,就是<strong>只能注册一个事处处理程序</strong>,如果你想注册多个事件处理程序是行不通的。比如:</p> <pre><code>&lt;!-- HTML --&gt; &lt;button&gt;单击我&lt;/button&gt; // Script let handler1 = function () { console.log('Handler1:', this) } let handler2 = function () { console.log('Handler2', this) } document.querySelector('button').onclick = handler1 document.querySelector('button').onclick = handler2 </code></pre> <p>当你点击<code>button</code>按钮时,浏览器控制台只会输出<code>hander2()</code>函数做的事情:</p> <p><img src="/sites/default/files/blogs/2018/1807/dom-model-1.png" alt="" /></p> <p>第一个函数<code>handler1()</code>不起作用。如果你想第一个函数也要起作用,那就需要使用接下来要说的事件模型 —— <strong>DOM Level 2模型</strong>。</p> <p>在基本事件模型中,如果要移除监听函数,可以通过给其事件赋值<code>null</code>来实现:</p> <pre><code>document.querySelector('button').onclick = null </code></pre> <h2>DOM Level 2模型</h2> <p>DOM level 2模型属于W3C标准模型,现代浏览器都支持该模型。在该事件模型中,一次事件共有三个过程:</p> <ul> <li><strong>事件捕获阶段(Capturing Phase)</strong>:事件从<code>document</code>一直向下传播到目标元素,依次检查经历过的节点是否绑定了事处监听函数(事件处理程序),如果有则执行,反之不执行</li> <li><strong>事件处理阶段(Target Phase)</strong>:事件到达目标元素,触发目标元素的监听函数</li> <li><strong>事件冒泡阶段(Bubbling Phase)</strong>:事件从目标元素冒泡到<code>document</code>,依次检查经过的节点是否绑定了事件监听函数,如果有则执行,反之不执行。</li> </ul> <blockquote> <p><strong>简而言之</strong>:事件一开始从文档的根节点流向目标对象(捕获阶段),然后在目标对向上被触发(目标阶段),之后再回溯到文档的根节点(冒泡阶段)。</p> </blockquote> <p><img src="/sites/default/files/blogs/2018/1807/dom-model-2.png" alt="" /></p> <p><em>图片来源于<a href="http://xxysy.com/quot;//www.w3.org/TR/DOM-Level-3-Events/#event-flow">W3C</a></em></p>" <p>DOM事件中这三个过程很复杂,但在这篇文章中不做深入阐述,如果感兴趣的话,后续的文章将会深入的探讨这方面的知识点。</p> <p>回到DOM Level 2事件模型中,要注册事件,必须使用<code>addEventListener()</code>方法。比如下面这个示例:</p> <pre><code>let handler = function () { // window的load事件要做的事情... } window.addEventListener('load',handler, false) </code></pre> <p>在基本事件模型中提到过,基本事件模型只能注册一个事件,但在DOM Level 2事件模型中可以,比如前面提到的按钮的<code>click</code>事件,我们可以注册多个事件:</p> <pre><code>let handler1 = function () { console.log('handler1:', this) } let handler2 = function () { console.log('handler2', this) } document.querySelector('button').addEventListener('click', handler1, true) document.querySelector('button').addEventListener('click', handler2, true) </code></pre> <p>这个时候点击按钮时,<code>handler1()</code>和<code>handler2()</code>两个函数都会被触发:</p> <p><img src="/sites/default/files/blogs/2018/1807/dom-model-3.png" alt="" /></p> <p>在DOM Level 2事件模型中,如果要移除事件处理程序,可以使用<code>removeEventListener()</code>方法。</p> <pre><code>let btn = document.getElementById('btn'); btn.addEventListener('click', handler, false); btn.removeEventListener('click', handler, false); </code></pre> <p>虽然DOM Level 2事件模型是W3C标准事件模型,但低于IE9的浏览器是不支持这种事件模型。所以在JavaScript事件模型中,还有第三种事件模型 —— <strong>IE事件模型</strong>。</p> <h2>IE事件模型</h2> <p>在IE事件模型中,需要使用<code>attachEvent()</code>和<code>detachEvent()</code>方法来触发事件和移除事件。在IE事件模型中,其有两个过程:</p> <ul> <li><strong>事件处理阶段(Target Phase)</strong>:事件到达目标元素,触发目标元素的监听函数</li> <li><strong>事件冒泡阶段(Bubbling Phase)</strong>:事件从目标元素冒泡到<code>document</code>,依次检查经过的节点是否绑定了事件监听函数,如果有则执行</li> </ul> <h2>DOM Level 3事件模型</h2> <p>DOM Level 3事件模型是DOM Level 2的事件模型的升级版,在DOM Level 2事件模型的基础上添加了更多的事件类型:</p> <ul> <li><strong>UI事件</strong>:当用户与页面上的元素交互时触发,如:<code>load</code>、<code>scroll</code></li> <li><strong>焦点事件</strong>:当元素获得或失去焦点时触发,如:<code>blur</code>、<code>focus</code></li> <li><strong>鼠标事件</strong>:当用户通过鼠标在页面执行操作时触发如:<code>dbclick</code>、<code>mouseup</code></li> <li><strong>滚轮事件</strong>:当使用鼠标滚轮或类似设备时触发,如:<code>mousewheel</code></li> <li><strong>文本事件</strong>:当在文档中输入文本时触发,如:<code>input</code>、<code>change</code></li> <li><strong>键盘事件</strong>:当用户通过键盘在页面上执行操作时触发,如:<code>keydown</code>、<code>keypress</code></li> <li><strong>合成事件</strong>:当为IME(输入法编辑器)输入字符时触发,如:<code>compositionstart</code></li> <li><strong>变动事件</strong>:当底层DOM结构发生变化时触发,如:<code>DOMsubtreeModified</code></li> </ul> <p>同时DOM3级事件也允许使用者自定义一些事件。在自定义事件称之为<strong>自定义事件模型</strong>。</p> <h2>自定义事件模型</h2> <p>事件模型的实现从设计模式的角度来看,是一种观察者模式或者也叫发布订阅模式,订阅者订阅一个消息,发布者发布这个消息,订阅者收到消息,这是一种数据流动的方式,使用这个模式的好处是,可以有多个订阅者,一个发布者,发布一条消息,可被多个订阅者收到。</p> <p>比如下面这样的一个事件模型:</p> <pre><code>;(function(global){ class Events { constructor(){ this.cache = {}; this.onceKeys = []; } on(key, fn){ if(!this.cache[key]) this.cache[key] = []; this.cache[key].push(fn); } one(key, fn){ this.cache[key]=[]; this.on(key, fn); this.onceKeys.push(key); } off(key, fn){ if(this.cache[key]) this.cache[key] = fn ? this.cache[key].filter(v=&gt;v !== fn) : []; } emit(key, ...args){ if(this.cache[key]){ this.cache[key].forEach(v=&gt;v.apply(null, args)) if(this.onceKeys.includes(key)){ this.cache[key] = []; this.onceKeys = this.onceKeys.filter(v=&gt;v!==key); } } } } global.Events = new Events(); })(this) </code></pre> <p>这是一个简单的自定义事件型型:</p> <ul> <li><code>on()</code>用于绑定事件,参数:事件名称,事件处理函数</li> <li><code>emit()</code>用于触发事件,参数:事件名称,传递给事件处理函数的参数</li> <li><code>off</code> 用于解除绑定的指定事件, 参数:事件名称,要解绑的事件函数</li> <li><code>one</code> 用于绑定一次性事件,只能触发一次,参数:事件名称,事件处理函数</li> </ul> <p>如果要使用,可以这样:</p> <pre><code>Events.on('cus', (a, b) =&gt; console.log(a+b)) Events.emit('cus', 1, 2); // =&gt; 3 Events.off('cus'); Events.emit('cus', 1, 2) // 只触发一次 Events.one('once', a =&gt; console.log(a)) Events.emit('once', 1); // =&gt; 1 Events.emit('once', 2); </code></pre> <h2>从事件模型中学到</h2> <p>从DOM事件模型上,我们可以学到很多。可以在项目中使用类似的解耦的概念。应用中的模块可以有很高的很复杂度,只要它的复杂度被封装隐藏在一套简单的接口背后。很多伟德19463331框架(比如<code>Backbone.js</code>)都是重度基于事件的,使用发布/订阅(Publish &amp; Subscribe)的方式来处理跨模块间的通信,这点跟DOM非常相似。</p> <p>基于事件的架构是极好的。它提供给我们一套非常简单通用的接口,通过针对这套接口的开发,我们能完成适应成千上万不同设备的应用。通过事件,设备们能准确地告诉我们正在发生的事情以及发生的时间,让我们随心所欲地做出响应。我们不再顾虑场景背后具体发生的事情,而是通过一个更高层次的抽象来写出更加令人惊艳的应用。</p> <h2>总结</h2> <p>这篇文章简单的介绍了DOM事件的模型。在JavaScript中常见的事件模型有:<strong>DOM基本事件模型</strong>、<strong>DOM Level 2事件模型</strong>、<strong>IE事件模型</strong>、<strong>DOM Level 3事件模型</strong> 和 <strong>自定义事件模型</strong>。每种事件模型都有其自己独具的特性。只有了解了DOM事件模型之后,才可以为后续的DOM事件打下一个基础。</p> <p>由于自己是JavaScript的初学者,如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-model.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-model.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/660.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/663.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM系列</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/666.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM事件</a></div></div></div> Mon, 23 Jul 2018 14:58:39 +0000 Airen 2434 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/9-biggest-mistakes-with-css-grid.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>如果你和我一样一直在关注CSS Grid布局的话,你应该知道@Rachel Andrew和@Jen Simmons都是CSS Grid 布局的布道师。两位女士一直都在推进Grid的特性和完善相关的特性。这几天看到@Jen Simmons录了一个视频,聊了一下CSS Grid布局相关的误区。</p> <h2>前言</h2> <p>在Web世界中,大家都知道,使用任何一项新技术都易于犯错,特别是像CSS Grid这样的与过去有很大变化的东西。初学者或者有一定经验的Web开发人员,都无法一时之间就能把控所有。@Jen Simmons录制了一个视频,向大家阐述了<strong>使用CSS Grid的九大误区</strong>,也是使用CSS Grid布局易犯的错误,并且在视频中提出了一些相关的建议,让大家在使用CSS Grid布局的时候能尽量的避免这些误区,甚至可以帮助一些同学改掉一些旧习惯。</p> <blockquote> <p>如果你英文够好,建议先直接观看下面这段视频。接下来的视频都来自于@Jen Simmons录制的视频,都放置在Youtube网站上的免费视频。不过需要正常观后的话,需要自备天梯。</p> </blockquote> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="281" src="//www.youtube.com/embed/0Gr1XSyxZy0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>接下来简单的看看这九个误区,以及相对应的一些资源,希望接下来的内容能更好的帮助大家理解这几个误区,以及增强这方面的知识点,更好的避开这些误区。</p> <h2>误区一:认为CSS Grid就是神</h2> <p>在《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/guide-css-layout.html">CSS布局指南</a>》一文中已经提到过,对于Web的布局,它将是一个永恒的话题。如果你对布局相关的知识有所了解,你应该知道,在CSS Grid出来之前,所有的布局方案都是针对的。直到CSS Grid出来之后,才有了二维的布局。就在此时,CSS Grid布局能解决很多以前一直无法解决的布局方案。</p> <p>就因为CSS Grid布局具有二维布局特性,造成了大家对CSS Grid的第一个误区:<strong>认为CSS Grid布局就是一神器,无所不能</strong>。事实上,这是一种对CSS Grid认识的误区。虽然CSS Grid布局能实现大部分的Web布局,但并不代表所有的布局都应该用CSS Grid来实现。正确的做法是:</p> <blockquote> <p>在适当的项目采用适当的布局方案。</p> </blockquote> <p>也因为这个误区,社区对这个现象有过很多的讨论,比如“Flexbox和Grid布局,哪个更好?”:</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/hs3piaN4b5I" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>有关于这方面的讨论还可以阅读:</p> <ul> <li><a href="//hackernoon.com/the-ultimate-css-battle-grid-vs-flexbox-d40da0449faf">The ultimate CSS battle: Grid vs Flexbox</a></li> <li><a href="//tutorialzine.com/2017/03/css-grid-vs-flexbox">CSS Grid VS Flexbox: A Practical Comparison</a></li> <li><a href="http://xxysy.com/quot;//rachelandrew.co.uk/archives/2016/03/30/should-i-use-grid-or-flexbox/">Shoul" I use Grid or Flexbox?</a></li> <li><a href="//redonion.se/flexbox-vs-css-grid-when-to-use-what-2/">Flexbox vs. CSS Grid, When to use what?</a></li> </ul> <p>正因为这样的讨论,在社区有一个共识。在Web布局当中,我们应该根据实际情况:<strong>Flexbox和Grid布局结合在一起使用</strong>:</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/dQHtT47eH0M" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>特别是在Card伟德1946手机版方面的布局,把Flexbox和Grid结合在一起将更显优势:</p> <ul> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/solving-problems-with-css-grid-and-flexbox-the-card-ui.html">使用CSS Grid和Flexbox制作Card</a></li> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/css-grid-flexbox-solving-real-world-problems.html">CSS Grid和Flexbox解决实际的布局问题</a></li> <li><a href="//medium.com/@petermouland/css-grid-flexbox-solving-real-world-problems-1cce3ecb2b51">CSS Grid + Flexbox Solving Real-world Problems</a></li> <li><a href="//getflywheel.com/layout/combine-flexbox-and-css-grids-for-layouts-how-to/">How to combine Flexbox and CSS grids for efficient layouts</a></li> </ul> <p>另外一方面,哪所现在的布局效果大部分是规规矩矩的正方形,但在不久的将来,Web的布局将会实现类似于杂志的布局效果。面对这样的布局效果,CSS Grid就显得心有余而力不足。从这一方面来说,CSS Grid并不是像大家所说的,它是万能的。</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/pOB75oTNhw0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>对于要实现类似于杂志风格的布局,那么还是需要<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/431.html"><code>clip-path</code></a>、<" href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/css-masking.html"><code>mask</code></a>和<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/418.html"><code>shape-outside</code></a>相关的属性的结" 。特别是离不开<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/418.html"><code>shape-outside</code>特性</a>。</p>" <h2>误区二:只使用百分比设置尺寸大小</h2> <p>Web的布局并不是一直都是固定宽度水平居中的布局,很多时候是有自适应的布局。实现自适应(流式布局)布局,在大家的脑海中应该是使用百分比来实现布局。但在CSS Grid布局中,并非一尘不变。主要是因为在CSS Grid的布局中,可以使用<code>min-content</code>、<code>max-content</code>和<code>minmax()</code>相关的特性:</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="https://www.youtube.com/embed/lZ2JX_6SGNI" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>有关于这方面的更详细的介绍还可以阅读下面相关的文章:</p> <ul> <li><a href="//www.w3.org/TR/css-sizing-3/#column-sizing">CSS Intrinsic &amp; Extrinsic Sizing Module Level 3</a></li> <li><a href="//alligator.io/css/css-grid-layout-minmax-function/">CSS Grid Layout: The Minmax Function</a></li> <li><a href="//www.hongkiat.com/blog/css-grid-layout-minmax/">CSS Grid Layout: How to Use <code>minmax()</code></a></li> <li><a href="http://xxysy.com/quot;//youtu.be/mVQiNpqXov8">MinMa" in CSS Grid</a></li> </ul> <p>除此之外,还可以使用CSS Grid布局独有的<code>fr</code>单位。也可以帮助我们实现类似于百分比的布局:</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/ZPtpzuRajzM" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>有关于<code>fr</code>单位更多的介绍可以阅读:</p> <ul> <li><a href="//css-tricks.com/introduction-fr-css-unit/">Introduction fr CSS unit</a></li> <li><a href="//www.hongkiat.com/blog/css-grid-layout-fr-unit/">Guide to CSS Grid Layout Fr Unit</a></li> <li><a href="//hackernoon.com/understanding-css-grids-fractional-units-fr-the-easy-way-5f43ee008f29">Understanding CSS Grids Fractional Units (FR) the easy way</a></li> <li><a href="//medium.com/flexbox-and-grids/what-you-didnt-know-about-the-css-fractional-unit-580bd62647e8">What You Didn’t know about the CSS Fractional Unit</a></li> </ul> <h2>误区三:需要断点</h2> <p><strong>断点</strong>是<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/responsive">Web响应式设计</a>中的一个概念。借用媒体查询在不同的断点处实现不一样的布局效果。因此,很多同学一直误以为,在CS" Grid布局中实现响应式布局也需要通过媒体查询来实现。而事实上并非如此。</p> <p>CSS Grid布局中有“<strong>隐式</strong>”和“<strong>显式</strong>”网格线的概念,同时在CSS Grid布局中使用<code>grid-template-columns: repeat(auto-fit, minmax(200px, fr))</code>这样的代码,在不使用媒体查询的情况下就可以很轻易的实现响应式布局。</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/tFKrK4eAiUQ" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <h2>误区四:被网络线编号搞糊涂</h2> <p>在CSS Grid布局中,网格线编号是一个很重要的概念。很多时候实现布局,都会借助网格线来实现。特别是在控制Web元素放置在具体的位置的时候,就可以使用网格线编号的特性。</p> <p>另外在CSS Grid布局中,对于网格线还有两个非常重要的概念,那就是<strong>隐式</strong>和<strong>显式</strong>网格线的编号。另外在布局时,除了使用显式的网格线编号之外,还会根据你的布局区域,创建隐式网格线。也就是说,自动创建隐式网格线。</p> <ul> <li><a href="//www.smashingmagazine.com/2017/10/naming-things-css-grid-layout/">Naming Things In CSS Grid Layout</a></li> <li><a href="//bitsofco.de/css-grid-terminology/">CSS Grid Layout Terminology, Explained</a></li> <li><a href="//webdesign.tutsplus.com/tutorials/quick-tip-name-your-css-grid-lines-just-in-case--cms-27844">Quick Tip: Name Your CSS Grid Lines, Just in Case</a></li> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/explicit-and-implicit-grid.html">CSS Grid布局:显式和隐式网格线</a></li> <li><a href="http://xxysy.com/quot;//youtu.be/-hmOZU7Zk10">Innovativ" &amp; Practical Graphic Design with CSS Grid</a></li> <li><a href="http://xxysy.com/quot;//youtu.be/FEnRpy9Xfes">Basic" of CSS Grid: The Big Picture</a></li> </ul> <h2>误区五:总是使用12列网格</h2> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/ZPtpzuRajzM" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>十二列网格,最早出处应该是<a href="http://xxysy.com/quot;//960.gs/">960gs网格系统</a>。在众多CS" Framework系统中都源于960gs创建了自己的网格系统。估计也是因为这个原因,很多使用CSS Grid布局的同学都误以为,它是12列网格系统的一种变身,而事实并非如此。CSS Grid 布局是单独的一个CSS模块。除了具备12列网格系统的功能之外,还具有独特的网格特性。</p> <h2>误区六:忽略行的幂值</h2> <p>在网格布局中,总是脱离不开行的概念。一般情况下,四条边可以组成一个行,而且在一个行中有N个单元格。而在CSS Grid布局中,可以使用<code>fr</code>、<code>minmax()</code>、<code>max-content</code>和<code>auto</code>组合在一起定义CSS Grid布局中的行。这样就可以让内容在不同的视窗大小实现较好的布局效果。从而将响应式设计提高到一个全新的水平。</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/EEOJZy_Gge4" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>另外,使用CSS Grid进行布局,在Web布局上可以真正的提供空白区域。这也正是行改变这一切的。</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="https://www.youtube.com/embed/YfIjFeBLhyA" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <ul> <li><a href="//www.slideshare.net/rachelandrew/unlocking-the-power-of-css-grid-layout">Unlocking the Power of CSS Grid Layout</a></li> <li><a href="//www.smashingmagazine.com/2017/11/css-grid-supporting-browsers-without-grid/">Using CSS Grid: Supporting Browsers Without Grid</a></li> </ul> <h2>误区七:一个框架</h2> <p>刚才提到了CSS Framework中的网格系统。这也造成一个误区,CSS Grid布局就是一个框架,一个布局框架。事实上,CSS Grid布局除了具有CSS Framework中的网格系统特性之外,还具备其他特性。这些特性是网格系统无法达到的。因为CSS Grid布局是一个二维布局,而网格系统事实是一个一维布局。</p> <h2>误区八:等待IE11的消亡</h2> <p>任何一个CSS特性,很多同学惧怕使用的原因之一就是浏览器支持度。那么CSS Grid的布局同样面临这样的问题。其实,最早提出CSS Grid布局模块是微软提出的功能模板,只不过后面其他的浏览器支持力度更快,造成一个现实就是其他浏览器比IE更早的实现CSS Grid布局的特性。</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/7msERxu7ivg" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>面对不能支持的浏览器,对于伟德19463331的同学而言再正常不过了。对于CSS Grid布局也是类似的。你只需要按这<a href="http://xxysy.com/quot;//www.youtube.com/playlist?list=PLbSquHt1VCf1kpv9WRGMCA9_Nn4vCLZ9Y">七个方面去做</a>,就可以解决相应的浏览器兼容问题。</p>" <ul> <li><a href="//rachelandrew.co.uk/archives/2016/11/26/should-i-try-to-use-the-ie-implementation-of-css-grid-layout/">Should I try to use the IE implementation of CSS Grid Layout?</a></li> <li><a href="//medium.com/@elad/supporting-css-grid-in-internet-explorer-b38669e75d66">Supporting CSS Grid in Internet Explorer</a></li> </ul> <h2>误区九:犹豫不决</h2> <p>像CSS Grid布局这样的布局新技术使用得实现旧的设计更加容易。更令人兴奋的是,我们可以做一些新的事情 —— 把网页上的平面设计提升到一个新的高度。那么使用CSS Grid布局,可以让我重新创作,实现更为复杂而又有意义的布局。通过这样的方式来了解CSS Grid布局的特性,以此更好地理解它对设计的意义。</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/qNtJ5p3h2A4" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <p>虽然CSS Grid布局非常的强大,但碍于一些实际上的原因,大部分人还在犹豫不决,惧怕浏览器的兼容性。就算是对这方面感兴趣的同学,现在也还只是的是着玩玩的心态。其实大家可以尝试着在自己的项目中使用CSS Grid来布局。比如@Jen就通过一个示例,一步步地指导你如何使用CSS Grid和一些其他的CSS特性,实现一个类似杂志风格的布局。</p> <div style="margin-bottom: 20px;padding: 2px; border: 1px solid #ccc;"> <iframe width="100%" height="480" src="//www.youtube.com/embed/OxrsO4aIjyc" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> </div> <h2>总结</h2> <p>这里简单的列了使用CSS Grid布局易于产生的误区。@Jen通过不同的视频向大家阐述了这些误区,而且在相应的视频中向大家介绍了如何避免这些陷阱和旧的习惯。视频中提到的一些建议和提示很值得我们大家花时间去学习和了解。如果你感兴趣,不信花时间去看看视频。如果你想了解更多的相关东西,建议你观看@Jen录制的一系列有关于布局相关的视频伟德1946网页版:<strong><a href="http://xxysy.com/quot;//www.youtube.com/layoutland">CS" Layout Land</a></strong>。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/9-biggest-mistakes-with-css-grid.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/9-biggest-mistakes-with-css-grid.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/CSS3"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS3</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/68.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/356.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS3 Grid Layout</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/355.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Grid</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/180.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Layout</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/130.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">布局</a></div></div></div> Thu, 19 Jul 2018 15:46:47 +0000 Airen 2433 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/the-complete-css-flex-box-tutorial.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="http://xxysy.com/quot;//twitter.com/js_tut">@js_tut</a>的新书《<" href="http://xxysy.com/quot;//amzn.to/2l25VFF">CS" Visual Dictionary</a>》里面的插画非常有意思。他在Medium上把<a href="//medium.com/@js_tut/css-tutorial-1-box-model-6ff80a9bbfda?source=placement_card_footer_grid---------0-44">盒模型</a>、<a href="//medium.com/@js_tut/the-complete-css-flex-box-tutorial-d17971950bdc">Flexbox</a>、<a href="//medium.com/@js_tut/css-grid-tutorial-filling-in-the-gaps-c596c9534611">Grid</a>三个部分放了一些出来。我觉得他提供的插画非常形象的阐述了这几个部分的知识点。今天把 Flexbox部分的插图直接拿来使用了,通过这些插图再次向大家阐述CSS Flexbox相关的知识。</p> <p>对于Flexbox的初学者,都希望知道Flexbox能做什么?时至今日,互联网上有关于Flexbox的伟德1946网页版绫罗满目,参差不齐。在这种情形之下,对于初学者而言并不是一件好事。那么今天这篇文章中所展示的插图,有助于初学者更好的掌握Flexbox的知识。当然对于有一定基础的同学,也能更好的加强其对Flexbox的印象和理解。</p> <p>那我们就开始吧!</p> <h2>Flex容器属性</h2> <blockquote> <p>Flex是一组规则,用于在父容器中自动扩展多列和多行。</p> </blockquote> <p>简单的理解就是Flex有一组样式规则,这些样式规则可以帮助你对内容按行或列来布局。而这些规则都将运用于Flex容器元素上。</p> <h3>display:flex</h3> <p>在Flexbox中与其他CSS属性略有不同。在Flexbox中有一个Flex容器的概念(主容器),在Flex容器中的直接子元素都是Flex项目。而我们刚才提到的Flex规则,都只用于Flex容器上。</p> <p><img src="/sites/default/files/blogs/2018/1807/flex-1.png" alt="" /></p> <p>从上图中我们可以得知,一旦你在某个元素上设置了<code>display:flex;</code>样式,那么该元素就自动变成了Flex容器,而容器中的直接子元素就被称为Flex项目。每个Flex容器都有起点(<code>flex-start</code>)和终点(<code>flex-end</code>)。</p> <h3>主轴(Main Axis)和 纵轴(Cross Axis)</h3> <p>Flexbox的布局是一维布局,Flex项目只能按行或列来排列(可以理解是以线性方式来排列)。由于这个原因,它有两个坐标轴。横轴称为主轴(Main Axis),纵轴为横轴(Cross Axis)。这两个轴始终是相互垂直的。</p> <blockquote> <p>这里需要特别注意,很多初学Flexbox的同学有一个误区,始终认为水平方向的横轴就是主轴,垂直方向的纵轴就是纵轴。事实上并非如此。因为<code>flex-direction</code>的值可以决定Flex容器中主轴和纵轴的方向。当<code>flex-direction</code>的值为<code>column</code>时,垂直方向的轴就变成了主轴,与其垂直的就是纵轴(水平方向的轴)。</p> </blockquote> <p>要控制主轴方向内容(Flex项目)的宽度和 Flex项目之间的间隙,可以使用<code>justify-content</code>属性。如果要控制纵轴方向的行为,需要使用<code>align-items</code>属性。</p> <p>比如说你想创建一个三列的布局,当你只有三个Flex项目的时候,它们一行就足够排列;一旦你有六个Flex项目的时候,从第四个开始自动会在第二行排列;如此类推,超过六个的时候会从第三行开始排列。如下图所示:</p> <p><img src="/sites/default/files/blogs/2018/1807/flex-2.png" alt="" /></p> <p><img src="/sites/default/files/blogs/2018/1807/flex-3.png" alt="" /></p> <p>事实上,我们在Flex容器上还可以使用其他的属性规则来控制它们的排列方式,和间距控制。稍后我们会介绍这些属性。</p> <p>在Flex容器上可以通过<code>flex-direction</code>和<code>flex-wrap</code>和其他一些属性来决定Flex项目的分布方式。</p> <p><img src="/sites/default/files/blogs/2018/1807/flex-4.png" alt="" /></p> <p>比如上图,在Flex容器中有<code>n</code>个Flex项目。默认情况下,这些Flex项目从左向右排列,而且是一行排列,哪怕是超出了Flex容器的宽度。那是因为<code>flex-direction</code>和<code>flex-wrap</code>的默认值分别为<code>row</code>和<code>nowrap</code>。只有改变其值之后,可以得到不一样的结果。</p> <h3>方向(<code>flex-direction</code>)</h3> <p>可以通过<code>flex-direction</code>的<code>row-reverse</code>值来颠倒Flex项目的排列方向。</p> <p><img src="/sites/default/files/blogs/2018/1807/flex-5.png" alt="" /></p> <blockquote> <p>使用<code>flex-direction</code>是和排版方向有很大的关系。我们习惯的排版方式是<code>ltr</code>(CSS中<code>direction</code>的值),如果是<code>ltr</code>,<code>flex-direction:row</code>,那么Flex项目是从Flex容器左向右排列,反之<code>rtl</code>,<code>flex-direction:row</code>就是从右向左排列。<code>flex-direction</code>取值为<code>row-reverse</code>类似。感兴趣的同学自己撸个码,这样会有更深的体会。</p> </blockquote> <div style="margin-bottom: 20px;"><iframe id="NBrxLW" src="//codepen.io/airen/embed/NBrxLW?height=400&amp;theme-id=0&amp;slug-hash=NBrxLW&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>包裹(<code>flex-wrap</code>)</h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-6.png" alt="" /></p> <p><code>flex-wrap</code>用来决定Flex项目的宽度和超过Flex容器的宽度时,Flex项目换不换行排列。前面也看到了,默认值为<code>nowrap</code>是不换行,如果你把值换成<code>wrap</code>,Flex容器容不下的时候就会自动换行。</p> <h3>流(<code>flex-flow</code>)</h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-7.png" alt="" /></p> <p>这里的流指的是Flex容器中Flex项目的排列方向。在Flexbox布局中除了<code>flex-direction</code>和<code>flex-wrap</code>来控制之外,还可以使用它们的的简写属性<code>flex-flow</code>。具体的情形主要有:</p> <p><img src="/sites/default/files/blogs/2018/1807/flex-8.png" alt="" /></p> <p><img src="/sites/default/files/blogs/2018/1807/flex-9.png" alt="" /></p> <p><img src="/sites/default/files/blogs/2018/1807/flex-10.png" alt="" /></p> <p><img src="/sites/default/files/blogs/2018/1807/flex-11.png" alt="" /></p> <p><img src="/sites/default/files/blogs/2018/1807/flex-12.png" alt="" /></p> <p><img src="/sites/default/files/blogs/2018/1807/flex-13.png" alt="" /></p> <p><img src="/sites/default/files/blogs/2018/1807/flex-14.png" alt="" /></p> <p>当<code>flex-direction</code>取值为<code>column</code>时,<code>flex-flow</code>属性的行为与前面的示例完全相同。</p> <p><img src="/sites/default/files/blogs/2018/1807/flex-15.png" alt="" /></p> <h3>横向对齐方式(<code>justify-content</code>)</h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-16.png" alt="" /></p> <p>上图的示例中,每行只有三个Flex项目。如果Flex项目很多的时候,这些属性同样适用。只不过看你是否配合前面的<code>flex-flow</code>来做其他相关的排列控制。</p> <p><img src="/sites/default/files/blogs/2018/1807/flex-17.png" alt="" /></p> <p>上图看到的效果都是<code>diplay: flex</code>时的场景。但<code>display</code>还可以取值为<code>inline-flex</code>。此时你看到的情景如下:</p> <p><img src="/sites/default/files/blogs/2018/1807/flex-18.png" alt="" /></p> <p><img src="/sites/default/files/blogs/2018/1807/flex-19.png" alt="" /></p> <h3>垂直对齐方式(<code>align-items</code>)</h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-20.png" alt="" /></p> <h2>Flex项目属性</h2> <p>除了Flex容器上的样式规则之外,在Flexbox布局中,还有一些属性是专用于Flex项目上的。</p> <h3><code>flex-basis</code></h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-21.png" alt="" /></p> <p><code>flex-basis</code>属性有点类似于<code>min-width</code>。它将根据内部内容扩展Flex项目的大小。</p> <h3><code>flex-grow</code></h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-22.png" alt="" /></p> <p><code>flex-grow</code>应用到一个Flex项目时,它将相对于同一行上所有其他Flex项目的大小的总和进行缩放。该值将根据指定的值自动调整。比如上图中的<code>flex-grow</code>分别设置为<code>1</code>、<code>7</code>、<code>3</code>和<code>5</code>的效果。</p> <h3><code>flex-shrink</code></h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-23.png" alt="" /></p> <p><code>flex-shrink</code>和<code>flex-grow</code>刚好相反。</p> <h3><code>flex</code></h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-24.png" alt="" /></p> <p><code>flex</code>是<code>flex-grow</code>、<code>flex-shrink</code>和<code>flex-basis</code>的简写属性。在Flexbox布局中,这部分相对而言是最为复杂的。涉及到的概念也多,而且不同的场景计算的姿势也略有不同。如果希望彻底搞清楚这三个属性的计算方式,建议花点时间阅读下面的伟德1946网页版:</p> <ul> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/flexbox-layout-and-calculation.html">深入理解 flex 布局以及计算</a></li> <li><a href="http://xxysy.com/quot;//www.codecamps.com/3-superpowers-of-the-flex-box-model/">" Superpowers of the Flex-Box Model — How flex-basis, flex-shrink and flex-grow work.</a></li> <li><a href="http://xxysy.com/quot;//gedd.ski/post/the-difference-between-width-and-flex-basis/">Th" Difference Between Width and Flex Basis</a></li> <li><a href="http://xxysy.com/quot;//medium.com/@tiffnogueira/understanding-flex-shrink-flex-grow-and-flex-basis-and-using-these-properties-to-their-full-e4b4afd2c930">Understandin" Flex Shrink, Flex Grow, and Flex Basis, and using these properties to their full potential</a></li> </ul> <h3><code>order</code></h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-25.png" alt="" /></p> <p>可以使用<code>order</code>属性来改变Flex项目的排列顺序。</p> <h3><code>justify-items</code></h3> <p><img src="/sites/default/files/blogs/2018/1807/flex-26.png" alt="" /></p> <p>这里要注意,<code>justify-items</code>和前面介绍的<code>justify-content</code>是不一样的。这个是用于Flex项目上,而<code>justify-content</code>是用于Flex容器上。</p> <h2>小结</h2> <p>这篇文章主要使用<a href="http://xxysy.com/quot;//twitter.com/js_tut">@js_tut</a>的新书《<" href="http://xxysy.com/quot;//amzn.to/2l25VFF">CS" Visual Dictionary</a>》里面的插画来阐述Flexbox布局中属性的基本使用。这些图只能形象告诉初学者怎么使用Flexbox相关的属性。不过这些只能学一些基础性的东西,但如果要深入的了解Flexbox相关的知识,还是不够的,还需要补充更多的知识点。如果你感兴趣的话,<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/157.html">可以猛击这里进行学习</a>。</p>" <p><strong>最后还是需要非常感谢@js_tut提供的这些插画。</strong>如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作更多优秀的伟德1946网页版。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/the-complete-css-flex-box-tutorial.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/the-complete-css-flex-box-tutorial.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/CSS3"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS3</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/68.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/157.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Flexbox</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/180.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Layout</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/130.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">布局</a></div></div></div> Tue, 17 Jul 2018 15:53:16 +0000 Airen 2432 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/the-css-paint-api.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>特别声明,本文根据<a href="//css-tricks.com/author/rumyragmail-com/">@RUTH JOHN</a>的《<a href="//css-tricks.com/the-css-paint-api/">The CSS Paint API</a>》一文所整理。</p> </blockquote> <p><a href="//drafts.css-houdini.org/css-paint-api-1/">CSS Paint API</a>是一个令人非常兴奋的东西,也是令人激动人心的时刻,它将开启CSS新的旅程。接下来让我们一起来看看它是什么,为什么会有它以及如何开始使用它。</p> <h2>CSS Paint API是什么</h2> <p>CSS Paint API只是CSS Houdini所有规范中的一部分。实际上,CSS Houdini为开发者提供了更低的CSS访问权限。这里没有开任何玩笑,事实上就是这样。</p> <p>CSS Paint API允许你可以在任何你想要的地方调用<code>paint()</code>函数。一个最常见的示例就是<code>background-image</code>属性,你可以使用<code>url()</code>函数来引用图像文件,比如:</p> <pre><code>area { background-image: url('assets/myimage.jpg'); } </code></pre> <p>CSS Paint API允许你调用<code>paint()</code>函数,并将其通过JavaScript定义一个<code>Paint Worklet</code>。可以把它想象成一段代码,允许你以编程的方式绘制任何你喜欢的东西。因为它是JavaScript,所以你可以把它变成动态的。API本身非常类似于HTML5的<code>&lt;canvas&gt;</code>的API(稍后我们将介绍它是如何工作的)。</p> <h2>酷而复杂</h2> <p>太好了!使用常规图片绝对没有什么错,而且我们一直都是这么做的。仅仅因为某样东西是新的并且可能很酷,这并不意味着我们所有人都必须开始把它用于项目上。然而,图像是静态的,但生成动态的东西想法是诱人的!</p> <p>我们都知道,<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/41.html">CSS的性线渐变</a>(<code>linear-gradient</code>)是非常强大的。<" href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/drawing-images-with-css-gradients.html">看看这些你就会认同我所说的</a>。但是,你能想象在没有多幅背景图像的情况下,创建这些分层模式的工作量会减少多少吗?不仅如此,深入到CSS Paint API中还可以帮助你理解在运行时如何生成这些图像,这是非常有用的(这也是我们将要做的)。</p> <p>那么浏览器还不支持的<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/using-conic-gradients-css-variables-create-doughnut-chart-output-range-input.html"><code>conic-gradient</code></a>又如何呢?也就是说,在没有任何Polyfill的情况之下,利用CSS Paint API可以创建一个<a href="//css-tricks.com/snippets/css/css-conic-gradient/"><code>conic-gradient</code></a>和一些属性,使其与实际的规范完全相同。所以,实际上你是在创造原生的Polyfill。这非常的棒!</p> <p>记住,这是CSS Houdini的更大的一部分。以下是来自Wiki对CSS Houdini的描述:</p> <blockquote> <p>CSS-TAG Houdini工作组(CSS Houdini)的目标是共同开发一些功能来增强Web上样式和布局的“<strong>魔力</strong>”!</p> </blockquote> <p>听起来不错,对吧!正是如此,这些新特性旨在允许Web开发人员扩展CSS本身的特性,提供更好的控制、跨浏览器的支持和原生的Polyfill。</p> <p>标准过程可能需要一段时间:<strong>从提出一个新的CSS特性,到编写一个规范,再到让浏览器供应商实现这个新规范</strong>(这个过程大家都知道)。由于开发人员常常渴望尽快开始使用一个新特性,我们必须考虑到浏览器老版本可能不支持。如果它尚未完全实现,更不用说典型的细微差别的跨浏览器实现。CSS Houdini可以允许我们自己实现跨浏览器的支持,而我们只需要等待浏览器供应端赶上来,但这并不会影响我们CSS新特性的使用,哪怕是未进入规范的新特性(前提是浏览器对CSS Houdini有全面的支持)。</p> <p>@Philip Walton在<a href="//www.smashingmagazine.com/2016/03/houdini-maybe-the-most-exciting-development-in-css-youve-never-heard-of/">Smashing Magazine的文章</a>中很好的解释了CSS Houdini的这些好处。你也可以看看@Ana Tudor是<a href="//css-tricks.com/what-houdini-means-for-animating-transforms/">如何使用CSS Houdini来创建复杂的动画的</a>。</p> <h2>现在可以用吗</h2> <p>你现在就可以用! CSS Paint API在Chrome 65中已得到支持。你也可以持续关注<a href="//caniuse.com/#feat=css-paint-api">caniuse.com</a>,这里有一个支持图表,随着时间的推移会不断更新。</p> <div style="margin-bottom: 20px;"><iframe src="//caniuse.com/css-paint-api/embed" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>哪一天表格是都是绿色的时候,代表你完全可以使用CSS Paint API。</p> <p>不管怎样,让我们看看如何使用它。接下来我把它的使用分成三个阶段。我们将在此过程中使用一些新的JavaScript特性。代码已经为你准备好了,但我们还是将会逐一介绍。</p> <h2>第一步:CSS部分</h2> <p>首先,我们需要在CSS中调用自己命名好的<code>worklet</code>。比如有这里,这个<code>worklet</code>命名为<code>awesomePattern</code>,所以在CSS可以像下面这样使用:</p> <pre><code>section { background-image: url('fallback.png'); background-image: paint(awesomePattern); } </code></pre> <p>虽然我们在CSS中通过<code>paint()</code>函数调用了名为<code>awesomePattern</code>的<code>worklet</code>,但它还不会起任何的作用。但不急,接着往下看。</p> <h2>第二步:JavaScript部分</h2> <p>现在,我们需要将我们的<strong>Paint Worklet</strong>添加到我们的JavaScript中,它正在加载另一个JavaScript文件,如下所示:</p> <pre><code>CSS.paintWorklet.addModule('patternWorklet.js'); </code></pre> <p>不过,就算你到这一步了,它依旧什么也不会发生,因为它在我们的<code>patternWorklet.js</code>文件中,所有的工作都将在其中完成。</p> <p>在<code>patternWorklet.js</code>文件中,我们需要注册一个<strong>Paint Worklet类</strong>:</p> <pre><code>registerPaint('awesomePattern', Shape); </code></pre> <p>我们调用<code>registerPaint()</code>函数,并传递我们想要调用的Paint Worklet,在本例中为<code>awesomePattern</code>,然后在本例中为将要编写的类为<code>Shape</code>。记住,在我们接下来要定义的类之后添加这个。与JavaScript中的函数提升不同,你需要在使用类之前定义类。</p> <p>接下来,将使用ECMAScript2015的类语法编写一个将为我们绘制背景的类。因为它现在被注册为一个Paint Worklet类:</p> <pre><code>class Shape { paint(ctx, geom, properties) { ctx.strokeStyle = 'white'; ctx.lineWidth = 4; ctx.beginPath(); ctx.arc( 200, 200, 50, 0, 2*Math.PI); ctx.stroke(); ctx.closePath(); } } </code></pre> <p>在<code>paint</code>回调中,我们有<code>ctx</code>、<code>geom</code>和<code>properties</code>三个参数。<code>ctx</code>和<code>&lt;canvas&gt;</code>元素中获得的2D上下文相同(好的,差不多:<code>&lt;canvas&gt;</code>元素允许读取像素数据,而CSS Paint API则不能)。它允许我们使用所有相同的方法来绘制,就像我们在<code>&lt;canvas&gt;</code>上绘制一样。在上面的例子中,我只是用<code>arc()</code>函数绘制了一个圆。</p> <p><code>arc()</code>函数的前两个值是圆位置的<code>X</code>和<code>Y</code>坐标,其在元素的左上角。但是,我希望这个圆在正中间,这就是<code>geom</code>的用处所在。它实际上传递的是<code>PaintSize</code>,也就是图像通常填充区域的大小,我们可以访问<code>width</code>和<code>height</code>信息,这也正是我们所需要的,使圆形位于正中心:</p> <pre><code>class Shape { paint(ctx, geom, properties) { let x = geom.width/2; let y = geom.height/2; ctx.strokeStyle = 'white'; ctx.lineWidth = 4; ctx.beginPath(); ctx.arc(x, y, 50, 0, 2*Math.PI); ctx.stroke(); ctx.closePath(); } } </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="rreeXb" src="//codepen.io/airen/embed/rreeXb?height=400&amp;theme-id=0&amp;slug-hash=rreeXb&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>很好,但这是一个非常简单的示例。你可以换圆圈换成更棒的,比如下面这个示例:</p> <div style="margin-bottom: 20px;"><iframe id="wxGWWm" src="//codepen.io/airen/embed/wxGWWm?height=400&amp;theme-id=0&amp;slug-hash=wxGWWm&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>上面这个示例,给类添加了一个叫做<code>drawStar</code>的方法,这个方法中有一大堆的<code>canvas</code>函数,用来绘制CSS-Tricks网站的Logo图标。</p> <h2>第三步:自定义属性</h2> <p>事实上,我们可以做更多的事情!可以复用CSS自定义属性的强大特性。我们都为此感到兴奋的原因之一,就是CSS自定义属性。</p> <p>假设我们想要改变CSS-Tricks的Logo图标的大小或颜色。我们可以把这些参数作为自定义属性放到CSS中,然后用回调函数中的第三个参数来访问它们。</p> <p>在CSS中添加一个<code>--star-scale</code>属性,它最终可以用来缩放Logo。另外一个是<code>--star-color</code>属性,可以很容易的改变Logo的颜色。</p> <pre><code>section { --star-scale: 2; --star-color: hsla(200, 50%, 50%, 1); background-image: paint(awesomePattern) } </code></pre> <p>回到我们的Paint Worklet类,我们需要访问这些自定义属性。我们可以使用<code>inputProperties()</code>方法来实现这一点,它使我们能够访问所有CSS属笥和它们设置的值:</p> <pre><code>static get inputProperties() { return ['--star-scale','--star-color']; } </code></pre> <p>现在,我们可以在<code>paint</code>方法中访问它们:</p> <pre><code>const size = parseInt(properties.get('--shape-size').toString()); </code></pre> <p>在代码中使用这个值。因此,如果我们改变CSS中的<code>--star-scale</code>或<code>--star-color</code>属性的值,这样就可以更新Logo的大小和颜色。</p> <blockquote> <p>同样需要注意的是,所有常见的CSS的<code>background</code>属性都可以正常的工作,比如<code>background-size</code>和<code>background-repeat</code>。这真的太棒了,而且仍然非常有用!</p> </blockquote> <h2>总结</h2> <p>这是非常强大的东西,不仅仅是定制的背景图片。想象在你的元素上有一个半边或双边。你通常可以使用<code>::before</code>或<code>::after</code>伪元素,或者可能使用经过精心设计的<code>box-shadow</code>。你可以用CSS Paint API和<code>border-image</code>属性来实现它。</p> <p>这个API真正的汇集了许多很酷的特性,比如worklets、ECMAScript2015的类和<code>canvas</code>。此外,它还提供了整个JavaScript交互层。你可以很容易地添加事件来更新自定义属性,从而更新图像本身,例如这个来自<a href="http://xxysy.com/quot;//github.com/GoogleChromeLabs/houdini-samples/tree/master/paint-worklet/ripple">@Surma写的案例</a>。这个Demo利用<code>click</code>事件来更新<code>requestAnimationFrame</code>函数中的属性,以便在用户每次点击<code>button</code>时创建动画。它甚至可以考虑点击的坐标。</p>" <p>这看起来似乎有点复杂,但让我们看看Houdini的其他部分,我们即将遇到:</p> <ul> <li><strong><a href="//drafts.css-houdini.org/css-layout-api-1/">CSS Layout API</a></strong>,它允许我们做一些类似<code>display:Layout("myCustomLayout")</code>的事情,对于这个API,典型的示例就是定制瀑布流布局,但范围要大得多</li> <li><strong><a href="//drafts.css-houdini.org/css-properties-values-api-1/">CSS Properties and Values API</a></strong>允许我们为自定义属性指定类型</li> <li><strong><a href="http://xxysy.com/quot;//wicg.github.io/animation-worklet/">CS" Animation Worklet API</a></strong>,它从主线程中获取和处理动画,这样一来就可以创建流畅的动画效果</li> </ul> <p>所以,不管你是否真的对这个特殊的新功能感兴趣,它都是一大堆新技术的一部分,将释放出大量的能量。这意这个空间,因为CSS会变得更棒!</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/the-css-paint-api.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/the-css-paint-api.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/translations"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">译文</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/68.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/553.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Houdini</a></div></div></div> Mon, 16 Jul 2018 16:38:04 +0000 Airen 2431 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-event-intro.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>如果你浏览过早期的Web网站,或许你已经发现了这些Web站点除了能提供查阅信息之外,无其他作用可言。这样的Web站点其实是非常无聊的。那是因为Web站点没有提供人与机器的互动行为。激不起用户的兴趣。</p> <p>造成这种现象的原因很简单。Web应用程序或者Web站点存应该是为了响应用户对它们所做的事情。好比,我们每天一大早起床时就想好了一天要做些什么,这样每天都有动力,也变得充实。那么在Web应用或Web网站上其实也是类似的,Web网站之后做的事情很大程度上取决于你告诉他们做什么。这样一来,Web网站会变得有趣的多。</p> <p>告诉应用程序做什么的方法是让它们对已知的事件做出反应。那么在今天开始,我们就开始来学习Web应用程序或网站中的事件,即DOM事件。首先在今天这篇文章中,我们将学习到什么是事件,以及如何使用它们。</p> <h2>事件是什么?</h2> <p>事实上,你创建的所有内容都可以按照下面的语句来建模:</p> <p><img src="/sites/default/files/blogs/2018/1807/dom-event-1.png" alt="" /></p> <p>这样的填空题有很多种答案。第一个空格填将一些事情;第二个空格描述了人们对该事件做出的反应。比如下面这样的示例:</p> <ul> <li>当 <strong>页面加载</strong> 时,<strong>播放一段视频</strong></li> <li>当 <strong>点击发生</strong> 时,<strong>提交已填好的表单</strong></li> <li>当 <strong>鼠标释放</strong> 时,<strong>弹出下人对话框</strong></li> <li>当 <strong>删除键按下</strong> 时,<strong>删除选中的图片</strong></li> <li>当 <strong>触摸屏幕</strong> 时,<strong>把卡片移出屏幕</strong></li> <li>当 <strong>文件下载发生</strong> 时,<strong>请更新进度条</strong></li> </ul> <p>这样的模型也适用于编码的世界中。而且这种模型用于事件中是非常有用的。其实<strong>事件</strong>只不过是一个信号。它告诉我们或用户发生了什么事情。这些信号在Web中,可以是鼠标点击、键盘上的按键,也可以是窗口大小被调整,甚至只是文档被加载。不过需要注意的是,这些信号可以是JavaScript中内置的任何东西,或者你为你的应用程序创建的定制的东西。回到我们的模型中,事件构成了前半部分:</p> <p><img src="/sites/default/files/blogs/2018/1807/dom-event-2.png" alt="" /></p> <p>事件定义了发生的事情,<strong>一个动作信号</strong>。模型的第二部分定义了模型中指定的事件做出的相应的反应:</p> <p><img src="/sites/default/files/blogs/2018/1807/dom-event-3.png" alt="" /></p> <p>我想,通过这样的一个事件模型,我们已经对什么是事件有了一个较清晰的概念,简单的来概述一下:</p> <blockquote> <p>事件是您在编程时系统内的发生的动作或者发生的事情,系统通过它来告诉您在您愿意的情况下您可以以某种方式对它做出回应。</p> </blockquote> <p>接下来,我们将围绕事件讨论一些重要的概念,并且观察它们在浏览器上是怎么工作的。</p> <h2>事件和JavaScript</h2> <p>考虑到事件的重要性,JavaScript提供了大量使用它们的特性。如果要处理事件,你需要做两件事:</p> <ul> <li>监听事件</li> <li>事件相应做出的反应</li> </ul> <p>看上去就两步,似乎很简单,但是不要忘记了,我们在处理的是JavaScript。哪怕是走错了一步,JavaScript将会给你带来巨大的创伤。<strong>简单性只是烟雾弹</strong>。也许我说得太夸张了(因为我是JS菜鸟),但我们很快就会发现。</p> <h3>监听事件</h3> <p>在Web应用程序或Web站点中,事件就是告诉浏览器发生了什么事情。浏览器会以此为据,给予响应(事件是客户端的一种处理机制,虽然以下以JavaScript语言为例,但并不代表事件机制与JavaScript这门语言存在直接联系,联系的建立是依靠客户端来实现的,事件机制本身并不是JavaScript语言的内容)。</p> <p>而客户端浏览器的交互模式的实现实际上是基于JavaScript的异步事件驱动模型编程的。维基百科是这样描述的:</p> <blockquote> <p>事件驱动程序设计(英语:Event-driven programming)是一种电脑程序设计模型。这种模型的程序运行流程是由用户的动作(如鼠标的按键,键盘的按键动作)或者是由其他程序的消息来决定的。相对于批处理程序设计(batch programming)而言,程序运行的流程是由程序员来决定。批量的程序设计在初级程序设计教学课程上是一种方式。然而,事件驱动程序设计这种设计模型是在交互程序(Interactive program)的情况下孕育而生的</p> </blockquote> <p>该模型可以用下面这张图来解释:</p> <p><img src="/sites/default/files/blogs/2018/1807/dom-event-4.png" alt="" /></p> <p>需要注意的是,很多时候你的应用程序会同时有很多事件被触发,而我们的任务是告诉应用程序只监听需要关心的事件。</p> <p>在JavaScript中,监听事件是由<code>addEventListener()</code>函数来处理的。其使用如下的方式来给元素添加事件监听:</p> <pre><code>element.addEventListener(&lt;event-name&gt;, &lt;callback&gt;, &lt;use-capture&gt;); </code></pre> <p><code>addEventListener()</code>函数中的参数具体含义:</p> <ul> <li><code>element</code>:要监听事件的元素或对象,通常是一个DOM元素,但它也可以是<code>document</code>,<code>window</code>或任何其他刚好触发事件的对象</li> <li><code>event-name(string)</code>:你想监听的事件的名称或类型。它可以是任何的标准DOM事件(<code>click</code>, <code>mousedown</code>, <code>touchstart</code>, <code>transitionEnd</code>,等等),当然也可以是你自己定义的事件名称</li> <li><code>callback(function)</code>:这个回调函数会在事件触发的时候被调用。相应的事件对象,以及事件的数据,会被作为第一个参数传入这个函数。这个函数也被称为<strong>事件处理程序</strong></li> <li><code>use-capture(boolean)</code>:这个参数决定了回调函数(<code>callback</code>)是否在“捕获(capture)”阶段被触发</li> </ul> <p>来看一个简单的示例:</p> <pre><code>document.addEventListener("click", changeColor, false); function changeColor () { document.body.style.backgroundColor = '#ffc926' } </code></pre> <p>上面的代码,<code>addEventListener()</code>被绑定到<code>document</code>对象。当监听到<code>click</code>事件发生时,<code>changeColor()</code>函数(即事件处理程序)来响应事件。<code>changeColor()</code>事件做的事情很简单,就是把<code>body</code>的<code>background-color</code>修改为<code>#ffc926</code>。</p> <p>从<code>addEventListenter()</code>函数监听元素事件来看,整个JavaScript事件机制包含了以下几个部分。</p> <h4>事件目标</h4> <p>事件目标(<code>Element</code>)很好理解,就是发生事件的对象或者与该事件相关的对象。其可以是一个<code>button</code>,一个<code>div</code>,一个<code>input</code>,甚至可以是<code>document</code>或<code>window</code>。而其确定是需要由需求来决定的。</p> <h4>事件类型</h4> <p>在JavaScript中,定义了一系列具有实际意义的事件类型,比如:</p> <ul> <li><code>click</code>:定义了单击事件</li> <li><code>mouseover</code>:定义了鼠标移动到某一个元素上的事件</li> <li><code>mouseout</code>:定义了鼠标移出某一个元素的事件</li> </ul> <p>有关于更多的事件类型及其含义,<a href="http://xxysy.com/quot;//developer.mozilla.org/zh-CN/docs/Web/Events">可以点击这里查阅</a>。</p>" <p>JavaSript中每一种事件类型都代表了一种不同的操作或者状态。不过不同的事件类型,浏览器对其兼容性不一,在实际使用时,需要做出对应的考量。不过,JavaScript中事件类型的划分还是有一定规则的,一般分为:</p> <ul> <li>鼠标事件,比如<code>mouseover</code>、<code>mouseout</code>、<code>click</code>等</li> <li>键盘事件,比如<code>keydown</code>、<code>keypress</code>、<code>keyup</code>等</li> <li>触屏事件,比如<code>touchstart</code>、<code>touchmove</code>、<code>touchenter</code>等</li> <li><code>window</code>事件,比如<code>load</code>、<code>unload</code>等</li> </ul> <p>还有其他的事件。这里就不一一列举了。</p> <h4>事件处理程序</h4> <p>事件处理程序是事件目标在响应时指定的事件类型时需要执行的程序。比如:</p> <pre><code>function changeColor () { document.body.style.backgroundColor = '#ffc926' } </code></pre> <p><code>changeColor()</code>函数就是我们的事件处理程序。</p> <h4>事件捕获</h4> <p>事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前就捕获它。</p> <p><code>addEventListener()</code>函数中第三个参数设置为<code>true</code>,即为事件捕获阶段。</p> <h3>事件响应</h3> <p>正如前面所介绍的,监听事件是由<code>addEventListener()</code>函数来处理的。事件处理程序将处理在事件被监听到后该做什么。即,放置在事件处理程序中的任何代码都将执行。</p> <h2>一个简单的事例</h2> <p>来看一个简单的示例。比如说,当你用鼠标点击浏览器屏幕(<code>document</code>),改变<code>body</code>的背景颜色。根据前面介绍的内容,JavaScript事件机制有四个部分:</p> <ul> <li>事件目标:<code>document</code></li> <li>事件类型:<code>click</code></li> <li>事件处理程序:<code>changeColor()</code></li> <li>事件捕获</li> </ul> <p>如果换到我们文章开头的模型中来,就是这样:</p> <p><img src="/sites/default/files/blogs/2018/1807/dom-event-5.png" alt="" /></p> <p>那么我们可以这么写我们的代码:</p> <pre><code>document.addEventListener("click", changeColor, false); function changeColor() { document.body.style.backgroundColor = "#FFC926"; } </code></pre> <h2>总结</h2> <p>好了,如查你坚持阅读到这里,那么你对事件有了一定的了解。请记住,你有<code>addEventListener()</code>函数,它允许你注册一个事件处理函数。当事件监听器正在监听的事件被触发时,将调用此事件处理程序函数。</p> <p>当然,我们这篇文章不仅仅是介绍<code>addEventListener()</code>函数,还介绍了事件的一些基本概念。主要是为了让大家对事件有初步的了解,如果你和我一样想继续深入学习DOM事件相关的知识,欢迎持续关注后续相关文章的更新。</p> <p>由于自己是JavaScript初学者,如果文章中有不对之处,欢迎路过的大婶拍正。如果您觉得这篇文章对您有所帮助,欢迎打个赏,让我有足够多的动力创作更多优秀的伟德1946网页版。(^_^)!!!</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-event-intro.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-event-intro.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/660.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/663.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM系列</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/666.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM事件</a></div></div></div> Mon, 16 Jul 2018 14:34:10 +0000 Airen 2430 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/guide-css-layout.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>特别声明,本文根据@Rachel Andrew的《<a href="//www.smashingmagazine.com/2018/05/guide-css-layout">Getting Started With CSS Layout</a>》一文整理。</p> </blockquote> <p>在过去几年中,CSS布局已经发生了巨大的变化,现在我们开发网站的方式也发生了巨大变化。现在我们有需要可选的CSS布局方式来开发我们的网站,这也就要求我们对这些方式能作出正确而双合适的选择。在这篇文章中,将会介绍各种CSS布局的基本使用方式以及使用的目的。</p> <p>如果你还是CSS方面的新手并且又想了解什么才是最好的布局方式,那么这篇文章正是你所需要的。如果你是一位比较有经验的开发者,想要了解一些关于CSS布局的最新知识,那么这篇文章值得你花费一点时间去阅读。当然,这篇文章并没有涉及CSS布局相关技术的细节,不然,围绕这个主题都可以写一本书了。不过,文章会对各种CSS布局做一个基本的概述,同时会给大家提供相关链接来进一步加强相关技术的学习。</p> <h2>正常文档流</h2> <p>如果你选择没有用任何CSS来改变页面布局的网页,那么HTML元素就会排列在一个<strong>正常流(Normal Flow)</strong>之中。在正常流中,元素盒子(任何一个HTML元素其实就是一个盒子)会基于文档的写作模式一个接一个地排列(根据不同的文档写作模式,排列方向不一样)。这就意味着,如果你的写作模式是水平的(句子是从左到右或从右到左写),正常流会垂直地一个接一个排列页面的块级元素。如果你是在一个垂直方向的写作模式下,句子是垂直方向书写的,那么块级元素会水平方向排列。</p> <p><img src="/sites/default/files/blogs/2018/1807/block-inline.png" alt="" /></p> <p>正常流是一种最苦的布局:当你的文档应用了CSS、创建了某些CSS布局,这些块就做了一个正常文档流之外的事。</p> <h3>通过页面结构来发挥正常文档流的优势</h3> <p>通过确保书写的页面具有良好的结构(HTML结构),如此一来就可以最大程度复用正常文档流所带来的优势。试想一下,如果浏览器中没有正常流,那么你创建的HTML元素都会堆积在浏览器的右上角。这就意味着,你必须指定所有的HTML元素的布局方式。</p> <p>有了正常流,哪怕是CSS加载失败了,用户仍然能阅读你的页面内容;同时,一些不使用CSS的工具(例如屏幕阅读器)会按照元素在文档中的位置来读取页面内容。另外从可用性角度来看,这无疑是非常有帮助的,同时也让开发者轻松了一些。如果你的内容顺序和用户预期的阅读顺序一致,那就不需要为了将元素调整到正确的位置而做大量的布局调整。当你继续往下阅读,将会发现,使用新的布局方式是如何让页面布局达到事半功倍的。</p> <p>因此,在思考如何布局之前,你需要认真思考你的文档结构,以及你希望用户以何种顺序来阅读文档中的内容。</p> <h3>脱离正常文档流</h3> <p>一旦页面有一个良好的结构,你就需要去决定如何利用它并将它变为我们需要的布局结构。这会涉及到脱离正常文档流(后续会详细阐述这部分)。我们有许多布局的“神器”可用,其中第一个要介绍的就是<code>float</code>,它是一个描述什么是脱离正常文档流的非常好的例子。</p> <h3>扩展阅读</h3> <ul> <li><a href="http://xxysy.com/quot;//www.w3.org/TR/CSS21/visuren.html#">Visua" formatting model</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Introduction">介" CSS 布局</a></li> </ul> <h2>浮动</h2> <p>浮动被用来将元素盒子向左或向右移动,同时让内容环绕其展示。</p> <p>要让一个元素进行浮动,需要给该元素的<code>flaot</code>属性设置为<code>left</code>或<code>right</code>。<code>float</code>的默认值为<code>none</code>。</p> <pre><code>.item { float: left } </code></pre> <p>值得注意的是,当你使某个元素浮动并让文字环绕它时,内容的行框(Line Box)被缩短。如果你让一个元素浮动,同时为紧跟着的包含文本的元素设置一个背景颜色,你会发现背景色会出在浮动元素下方。</p> <p><img src="/sites/default/files/blogs/2018/1807/float-background.png" alt="" /></p> <p>如果想要在浮动元素和环绕的文本之间有一定的间距,需要给浮动元素设置<code>margin</code>。在文本元素上设置<code>margin</code>只会让其相对于容器缩进。例如在下面这个例子中,你就需要为左侧浮动的图片设置右边距和下边距。</p> <div style="margin-bottom: 20px;"><iframe id="vaEywa" src="//codepen.io/airen/embed/vaEywa?height=400&amp;theme-id=0&amp;slug-hash=vaEywa&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>清除浮动</h3> <p>一旦对一个元素进行了浮动,所有接下来的元素都会环绕它,直到内容处理它下方且开始应用正常文档流。如果想要避免这种情形,可以手动清除浮动。</p> <p>如果不想要在某个元素受到其之前的浮动元素影响时,可以为其添加<code>clear</code>属性。<code>left</code>值表示清除左边的浮动,<code>right</code>值表示清除右浮动,<code>both</code>值表示清除左右两边的浮动。</p> <pre><code>.clear { clear: both; } </code></pre> <p>如果希望元素在浮动元素之后开始排列,那么上面的代码可以达到你的需求。如果你发现在容器内有一个浮动元素,同时容器内文本内容过短时,就会出现问题。文本盒子会被绘制在浮动元素下,然后接下来的部分会以正常流方式绘制在其后。</p> <p><img src="/sites/default/files/blogs/2018/1807/float-needs-clearing.png" alt="" /></p> <p>为了避免这种情况,我们需要为容器中某个元素应用<code>clear</code>属性。我们可以在容器中最后添加一个空元素并设置<code>clear</code>属性。但是在某些情况之下可能无法使用这种方式(例如一些CMS系统生成的页面,HTML结构是很难重构)。因此,最常见的清除浮动的方案是:在容器内添加一个CSS伪元素,并将其<code>clear</code>的值设置为<code>both</code>。</p> <div style="margin-bottom: 20px;"><iframe id="YjPNBo" src="//codepen.io/airen/embed/YjPNBo?height=400&amp;theme-id=0&amp;slug-hash=YjPNBo&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>块级格式化上下文</h3> <p>清除浮动的另一个方法是在容器内创建BFC(块格式化上下文,Block Formatting Context)。一个BFC元素完全包裹住了它内部的所有元素,包括内部的浮动元素,保证浮动元素不会超出其底部。创建BFC方式有很多种,其中最常见的方法是给其<code>overflow</code>属性设置为<code>visible</code>之外的值。</p> <pre><code>.container { overflow: auto; } </code></pre> <p>像上面这样使用<code>overflow</code>,一般情况下是有效的,可以清除浮动。但是在某些情况下,可能会裁掉一些<code>box-shadow</code>或是出现滚动条(事实上你并不想滚动条出现)。同时,它在样式表中看起来也有点混乱:设置<code>overflow</code>其实是想要滚动条的出现,而此处却仅仅是用来清除浮动。那么设置<code>overflow</code>到底是想要滚动条出现,还是清除浮动呢?</p> <p>为了使用清除浮动的意图更加直观,并且避免BFC的负面影响,可以使用<code>display</code>的<code>flow-root</code>来清除浮动。<code>display: flow-root</code>做的唯一的一件事就是去创建BFC,因此可以避免其他创建BFC方法带来的副作用。</p> <pre><code>.container { display: flow-root; } </code></pre> <h3>浮动的一些遗留用法</h3> <p>在新的布局方式出现以前,<code>float</code>经常用来创建多列布局。我们会给一系列元素设置<code>width</code>并且将它们一个接一个的进行浮动。通过为浮动元素设置一些精细的百分比大小可以创建类似网格的效果。</p> <p>我不建议在当下仍然过渡的使用浮动来布局。但是,在现有的网站中,这种布局方式仍然会存在许多年。因此,当你碰到一个页面到处是<code>float</code>的时候,可以确定它就是用的浮动布局。</p> <h3>扩展阅读</h3> <ul> <li><a href="//www.w3.org/TR/css-page-floats-3/">CSS Page Floats</a></li> <li><a href="//css-tricks.com/snippets/css/clear-fix/">The Clearfix: Force an Element To Self-Clear its Children</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/CSS/float">float</a></li>" <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/CSS/clear">clear</a></li>" <li><a href="//www.smashingmagazine.com/2017/12/understanding-css-layout-block-formatting-context/">Understanding CSS Layout And The Block Formatting Context</a></li> <li><a href="//css-tricks.com/clearfix-a-lesson-in-web-development-evolution/">Clearfix: A Lesson in Web Development Evolution</a></li> <li><a href="//alistapart.com/article/css-floats-101">CSS Floats 101</a></li> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/389.html">BFC</a></li>" <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/83.html">Float</a></li>" <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/display-flow-root.html">flow-root</a></li> </ul> <h2>定位</h2> <p>想要把一个元素脱离正常文档流或者改变其在正常文档流中的位置,可以使用CSS的<code>position</code>属性。在正常文档流中,元素的<code>position</code>的值为<code>static</code>(也是<code>position</code>的默认值)。在块级维度上元素会一个接一个排列下去,当你滚动页面时,元素也会随着滚动。</p> <p>当改变元素<code>position</code>属性时,通常也会设置一些偏移量来使元素相对于参照物进行一定的移动。不同的<code>position</code>值会产生不同的参照物。</p> <h3>相对定位</h3> <p>如果一个元素设置了<code>position</code>属性的值为<code>relative</code>,那么它偏移的参照位是其自身原先在正常文档流中的位置。可以使用<code>top</code>、<code>right</code>、<code>bottom</code>和<code>left</code>属性将元素相对其正常文档流位置进行移动。</p> <pre><code>.item { position: relative; bottom: 50px; } </code></pre> <p>请注意,页面上的其他元素并不会因该元素的位置变化而受到影响。该元素在正常文档流中的位置会被保留,因此你需要自己去处理一些元素内容覆盖的情况。</p> <div style="margin-bottom: 20px;"><iframe id="NBPwdP" src="//codepen.io/airen/embed/NBPwdP?height=400&amp;theme-id=0&amp;slug-hash=NBPwdP&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>绝对定位</h3> <p>元素的<code>position</code>属性值为<code>absolute</code>可以将其完全脱离正常文档流。其原本占据的空间也会被移除。该元素定位会相对于视窗容器,除非其某个祖先元素的<code>position</code>值设置了非<code>static</code>。</p> <p>因此,当你为某个元素设置<code>position: absolute</code>时,首先发生的变化是该元素会定位在视窗的左上角。你可以通过<code>top</code>、<code>right</code>、<code>bottom</code>和<code>left</code>属性设置偏移量,将元素移动到你想要的位置。</p> <pre><code>.item { position: absolute; top: 20px; right: 20px; } </code></pre> <p>通常情况下,你并不希望元素相对于视窗进行定位,而是相对于容器元素。在这种情况下,需要为容器元素设置一个除了默认值<code>static</code>之外的其他值。</p> <p>由于给元素设置<code>position:relative</code>并不会将其从正常文档流中移除,所以一般情况之下是一个很好的选择。给你想要相对的容器元素设置<code>position:relative</code>,就可以让绝对定位的元素相对其进行偏移。</p> <div style="margin-bottom: 20px;"><iframe id="QBwOJG" src="//codepen.io/airen/embed/QBwOJG?height=400&amp;theme-id=0&amp;slug-hash=QBwOJG&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>固定定位</h3> <p>大多数情况下,<code>position:fixed</code>的元素会相对于视窗定位,并且会脱离正常文档流,同样也不会保留该元素所点点据的空间。当页面滚动时,固定的元素会留在相对于视窗的位置,而其他正常文档流中的内容则和往常一样滚动。</p> <pre><code>.item { position: fixed; top: 20px; left: 100px; } </code></pre> <p>当你想要一个固定导航栏一直停留在屏幕上时,这种做法非常有效。和其他<code>position</code>值(除<code>static</code>之外)一样,也可能会造成一些元素被遮盖,需要小心保证页面内容的可读而不会被固定元素遮挡。</p> <div style="margin-bottom: 20px;"><iframe id="pZvdXr" src="//codepen.io/airen/embed/pZvdXr?height=400&amp;theme-id=0&amp;slug-hash=pZvdXr&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>如果需要使一个固定元素不是相对于视窗进行定位,那么需要为容器元素设置<code>transform</code>、<code>perspective</code>或<code>filter</code>三个属性之一(不能取其默认值<code>none</code>)。这样固定的元素就会相对于该块元素偏移,而不是相对于视窗。</p> <h3>黏贴定位(Sticky)</h3> <p>设置<code>position: sticky</code>会让元素在页面滚动时如同在正常流中,但当其滚动到相对于视口的某个特定位置时就会固定在屏幕上,如同<code>fixed</code>一般。这个属性值是<code>position</code>属性的一个新值,在浏览器兼容性上会差一些,但在不兼容的浏览器中会被忽略并会退到正常的滚动情况。</p> <pre><code>.item { position: sticky; top: 0; } </code></pre> <p>下面的代码展示了如何创建一个非常流行导航栏效果:导航栏会随着页面滚动,而当导航栏滚动到页面顶部时则会固定在顶部位置。</p> <div style="margin-bottom: 20px;"><iframe id="pZvpgp" src="//codepen.io/airen/embed/pZvpgp?height=400&amp;theme-id=0&amp;slug-hash=pZvpgp&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>扩展阅读</h3> <ul> <li><a href="//www.w3.org/TR/css-position-3/">CSS Positioned Layout Module Level 3</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Positioning">Positioning</a></li>" <li><a href="//css-tricks.com/position-sticky-2/"><code>position: sticky;</code></a></li> <li><a href="//zellwk.com/blog/css-positions/">Understanding and Using CSS Positions</a></li> <li><a href="//alistapart.com/article/css-positioning-101">CSS Positioning 101</a></li> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/229.html">十步图解CSS的<code>position</code></a></li>" <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/advanced-html-css-lesson2-detailed-css-positioning.html">HTML和CSS高级指南之二:定位详解</a></li> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/position-and-z-index.html">你对Position的了解程度有多少?</a></li>" </ul> <h2>Flex布局</h2> <p>Flexbox布局是一种用于一维布局而设计的布局方法。一维的意思是你希望内容是按照行或者列来布局。你可以在元素上将<code>display</code>设置为<code>flex</code>值,把该元素为变弹性布局。</p> <pre><code>.container { display: flex; } </code></pre> <p>该容器的直接子元素会变为弹性项(Flex Item),并按行排列。</p> <div style="margin-bottom: 20px;"><iframe id="zLxROO" src="//codepen.io/airen/embed/zLxROO?height=400&amp;theme-id=0&amp;slug-hash=zLxROO&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>Flexbox的轴</h3> <p>在上面的示例中,弹性项在行内是从起始位置开始排列,而不是说它们是左对齐。这些元素会按行排列是因为<code>flex-direction</code>的默认值为<code>row</code>,<code>row</code>代表了文本的行文方向。由于我们的工作环境是英文,一种自左向右的语言,行的开始位置就在左边,因此我们的弹性项也是从左边开始的。因此,<code>flex-direction</code>的值被定义为Flexbox的主轴(Main Axis)。</p> <p>交叉轴(Cross Axis)则是和主轴相互垂直的一条Flexbox轴。如果<code>flex-direction</code>是<code>row</code>,并且弹性项是按照内方向排列的,那么交叉轴就是块级元素的排列方向。如果<code>flex-direction</code>是<code>column</code>,那么弹性项就会以块级元素排列的方向排列,然后交叉轴就会变为<code>row</code>。</p> <p>如果你习惯于从主轴与交叉轴的角度来使用Flexbox盒子,那么一切会变得非常简单。</p> <h3>方向和顺序</h3> <p>Flexbox允许我们通过<code>flex-direction</code>属性设置为<code>row-reverse</code>或<code>column-reverse</code>值来改变主轴上弹性荐的方向。</p> <div style="margin-bottom: 20px;"><iframe id="ajzqGB" src="//codepen.io/airen/embed/ajzqGB?height=400&amp;theme-id=0&amp;slug-hash=ajzqGB&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>当然,也可以通过<code>order</code>属性来改变某一个弹性项的顺序。但是要特别注意,这可能会给那些通过键盘(而非鼠标或触屏)访问你的网站的用户带来一些麻烦,因为<code>tab</code>的顺序是页面内元素在源码中的顺序而非显示顺序。你可以阅读之后的“显示和文档顺序”部分来了解更多相关内容。</p> <h3>flex属性</h3> <p><code>flex</code>的属性是用来控制弹性项在主轴上空间大小的。他是下面三个属性的简写方式:</p> <ul> <li><code>flex-grow</code></li> <li><code>flex-shrink</code></li> <li><code>flex-basis</code></li> </ul> <p>简写的<code>flex</code>属性会有三个值,第一个值是<code>flex-grow</code>,第二个是<code>flex-shrink</code>,第三个是<code>flex-basis</code>。</p> <pre><code>.item { flex: 1 1 200px; } </code></pre> <p><code>flex-basis</code>会为弹性项设置未拉伸和压缩时的初始大小。在上面的例子中,大小是<code>200px</code>,因此我们会给每个项<code>200px</code>的空间大小。但是大多数情况下容器元素大小不会正好被分为许多<code>200px</code>大小的项,而是可能有一些不足或剩余空间。<code>flex-grow</code>和<code>flow-shrink</code>属性允许我们在容器大小不足或有空余时控制各个弹性项的大小。</p> <p>如果<code>flex-grow</code>的值是任意的正数,那么弹性项会被允许拉伸来占据更多的空间。因此,在上面的例子中,当各项被设为<code>200px</code>后,所有多余的空间会被每个弹性项平分并填满。</p> <p>如果<code>flex-shrink</code>的值为任意的正数,那么当弹性项被设置了<code>flex-basis</code>后,元素溢出容器时会进行收缩。在上面这个CSS的例子中,如果容器空间不足,每个弹性项会等比例缩放以适应容器的大小。</p> <p><code>flex-grow</code>和<code>flex-shrink</code>的值可以是任意的正数。一个具有较大<code>flex-grow</code>值的弹性项会在容器有剩余空间时拉伸更大的比例;而一个具有更大<code>flex-shrink</code>值的项则会在容器空间不足时被压缩的更多。</p> <div style="margin-bottom: 20px;"><iframe id="PBwQgX" src="//codepen.io/airen/embed/PBwQgX?height=400&amp;theme-id=0&amp;slug-hash=PBwQgX&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>理解这些属性是理解如何使用弹性布局的关键,下面列出的一些资源会帮助我们进一步学习其中的细节。当你需要在容器的一个维度上拉伸或者压缩一些元素时,你可以考虑使用弹性盒子模型。如果你发现你正尝试在行和列两个维度上排列你的内容,你需要的是网格模型(grid),这时弹性盒子模型很可能不是最合适的工具了。</p> <h3>扩展阅读</h3> <ul> <li><a href="//www.w3.org/TR/css-flexbox-1/">CSS Flexible Box Layout Module Level 1</a></li> <li><a href="//css-tricks.com/snippets/css/a-guide-to-flexbox/">A Complete Guide to Flexbox</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Flexbox">弹性盒子</a></li>" <li><a href="//medium.com/@js_tut/the-complete-css-flex-box-tutorial-d17971950bdc">The Complete CSS Flex Box Tutorial</a></li> <li><a href="http://xxysy.com/quot;//gedd.ski/post/the-difference-between-width-and-flex-basis/">Th" Difference Between Width and Flex Basis</a></li> <li><a href="http://xxysy.com/quot;//medium.freecodecamp.org/understanding-flexbox-everything-you-need-to-know-b4013d4dc9af">Understandin" Flexbox: Everything you need to know</a></li> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/157.html">Flexbox教" @伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】</a></li> </ul> <h2>Grid布局</h2> <p>CSS Grid布局是一种用来进行二维布局的技术。二维意味着你希望按照行和列来排布你的内容。和Flexbox类似,Grid布局也需要设置一个<code>display</code>值。你可以为容器元素设置<code>display: grid</code>,并且使用<code>grid-template-columns</code>和<code>grid-template-rows</code>属性来控制网格中的行与列。</p> <pre><code>.container { display: grid; grid-template-columns: 200px 200px 200px; grid-template-rows: 200px 200px; } </code></pre> <p>上面这段CSS会创建一个行列元素大小固定的网格。不过这也许并不是你希望的。默认值为<code>auto</code>,你可以认为这代表了“让格子尽可能的大”。如果你每没有指定行的大小,所有添加进来的行内容大小都会被置为<code>auto</code>。一种常用的模式是为网格制定列宽度,但是允许网格按需添加行。</p> <p>你可以使用任意的长度单位或时百分比来设置行与列,同时你可以使用为网格系统所创造的新的单位——<code>fr</code>。<code>fr</code>是一种弹性单位,它可以指定网格容器内的空间被如何划分。</p> <p>网格会替你计算与分配空间,你不需要去计算元素的百分比去适应容器大小。在下面这个例子中,我们使用<code>fr</code>来创建网格的列,这使得网格的列可以自适应。同时我们还使用了<code>grid-gap</code>来保证元素间的间距(关于网格内元素与的间距会在“对齐”这一部分详细介绍)。</p> <div style="margin-bottom: 20px;"><iframe id="KBpmMG" src="//codepen.io/airen/embed/KBpmMG?height=400&amp;theme-id=0&amp;slug-hash=KBpmMG&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>这个就像Flexbox布局中的<code>flex-grow</code>或<code>flex-shrink</code>一样,<code>fr</code>会根根Grid容器的空间给Grid项目分配可用空间。如果<code>fr</code>的值较大,这意味着对应的网格轨道可以获得更多可用空间。你也可以将<code>fr</code>和固定长度混合在一起使用。在计算<code>fr</code>之前,长度所需的空间将从可用空间中减去。</p> <div style="margin-bottom: 20px;"><iframe id="rrVmyX" src="//codepen.io/airen/embed/rrVmyX?height=400&amp;theme-id=0&amp;slug-hash=rrVmyX&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>网格术语</h3> <p>网格系统总是有两个轴:行内轴(Inline Axis)表示页面中文字的文字排列的方向,块轴(Block Axis)表示页面中块级元素的排列方向。</p> <p>一个被设置为<code>display: grid</code>的元素就是所谓的网格容器。在网格容器中会有网格线(Grid Line),网格线就是你在指定<code>grid-template-columns</code>和<code>grid-template-rows</code>时网格中行列所生成的。网格中的最小单位(也就是被四条网格线截取生成的区域)被成为网格单元格(Grid Cell),进一步的,由若干个单元格组成的矩形区域被成为网格区域(Grid Area)。</p> <p><img src="/sites/default/files/blogs/2018/1807/grid-lines.png" alt="" /></p> <p><em>上图中的虚线是网格线</em></p> <p><img src="/sites/default/files/blogs/2018/1807/grid-track.png" alt="" /></p> <p><em>两条网格线之间的区域是网格轨道(网格的行或列)</em></p> <p><img src="/sites/default/files/blogs/2018/1807/grid-cells-areas.png" alt="" /></p> <p><em>网格单元格和网格区域</em></p> <h3>网格的自动排列规则</h3> <p>一旦你创建了网格,那么网格容器的直接子元素就会开始将它们自己一个一个地放置在网格的单元格中。子元素的放置是依据网格的自动排列规则。这些规则确保了网格内元素是被安排在各个空的单元格中,而不会彼此遮盖。</p> <p>网格中任何没有被进行定位的直接子元素都会根据自动排列规则进行放置。在下面这个列子中,我让每三个元素中的第一个占据两行,但仍然从起始行开始去自动排列。</p> <div style="margin-bottom: 20px;"><iframe id="ejNWVO" src="//codepen.io/airen/embed/ejNWVO?height=400&amp;theme-id=0&amp;slug-hash=ejNWVO&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>基于行或列的定位</h3> <p>定位网格元素最简单的方式是使用基于行或列网格的定位方法,只需告诉浏览器从哪一排到哪一排来进行合并。例如,如果你需要一个<code>2 x 2</code>的网格区域,你可以将指定元素从第一行开始到第三行、从第一列开始到第三列,这样就可以覆盖到四个单元格。</p> <pre><code>.item { grid-column-start: 1; grid-column-end: 3; grid-row-start: 1; grid-row-end: 3; } </code></pre> <p>这些属性可以用缩写来表示:<code>grid-column</code>和<code>grid-row</code>,其中起一个值代表起始值,第二个值代表结束值。</p> <pre><code>.item { grid-column: 1 / 3; grid-row: 1 / 3; } </code></pre> <p>你也可以让网格项占据同一个单元格。支持一些内容间会覆盖的设计。网格项会像通常网页中的元素那样叠起来,在<code>html</code>源码中下面的网格项会叠在其他元素上面。你仍然可以用<code>z-index</code>来控制它的堆叠顺序。</p> <div style="margin-bottom: 20px;"><iframe id="rrVmra" src="//codepen.io/airen/embed/rrVmra?height=400&amp;theme-id=0&amp;slug-hash=rrVmra&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>通过命名区域来定位元素</h3> <p>你可以通过命名网格区域来定位网格中的元素。要是用这种方式,你需要给每个元素一个名字,然后通过<code>grid-template-areas</code>属性的值来描述布局方式。</p> <pre><code>.item1 { grid-area: a; } .item2 { grid-area: b; } .item3 { grid-area: c; } .container { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; grid-template-areas: "a a b b" "a a c c"; } </code></pre> <p>使用这种方式有几个需要注意的点。如果你想要合并一些单元格作为你的网格项,你需要重复元素的名字。网格区域需要能形成一个完整的矩形 —— 每个单元格都需要被填入一个值。如果你想要空出某些单元格,那就需要使用<code>.</code>这个值。例如在下面的CSS里我将最右下角的单元格留空。</p> <pre><code>.container { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; grid-template-areas: "a a b b" "a a c ."; } </code></pre> <p>你也可以通过下面这个Demo的代码来看看实际的布局效果。</p> <div style="margin-bottom: 20px;"><iframe id="ejNWbN" src="//codepen.io/airen/embed/ejNWbN?height=400&amp;theme-id=0&amp;slug-hash=ejNWbN&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>这篇文章只包括了CSS Grid布局的一些初级内容,其中还有非常多的内容值得学习,下面的一些资料可以帮助你进一步学习。一些伟德1946手机版或整个页面的布局都可以使用网格。如果你需要在两个维度进行布局,网格布局是一个不错的选择 —— 不论需要布局的区域的大小。</p> <h3>扩展阅读</h3> <ul> <li><a href="//www.w3.org/TR/css-grid-2/">CSS Grid Layout Module Level 2</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout">CS" Grid Layout</a></li> <li><a href="http://xxysy.com/quot;//gridbyexample.com/">Gri" by Example</a></li> <li><a href="http://xxysy.com/quot;//www.youtube.com/channel/UC7TizprGknbDalbHplROtag">Layou" Land</a></li> <li><a href="//css-tricks.com/snippets/css/complete-guide-grid/">A Complete Guide to Grid</a></li> <li><a href="//learncssgrid.com/">Learn CSS Grid</a></li> <li><a href="http://xxysy.com/quot;//www.smashingmagazine.com/2018/04/best-practices-grid-layout/">Bes" Practices With CSS Grid Layout</a></li> <li><a href="http://xxysy.com/quot;//www.smashingmagazine.com/2018/02/generated-content-grid-layout/">Stylin" Empty Cells With Generated Content And CSS Grid Layout</a></li> <li><a href="//www.smashingmagazine.com/2017/11/css-grid-supporting-browsers-without-grid/">Using CSS Grid: Supporting Browsers Without Grid</a></li> <li><a href="//www.smashingmagazine.com/2017/09/css-grid-gotchas-stumbling-blocks/">CSS Grid Gotchas And Stumbling Blocks</a></li> <li><a href="//www.smashingmagazine.com/2017/10/naming-things-css-grid-layout/">Naming Things In CSS Grid Layout</a></li> <li><a href="//github.com/valentinogagliardi/awesome-css-grid">Awesome CSS Grid</a></li> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/355.html">Gri" Layout tutorial</a></li> <li><a href="http://xxysy.com/quot;//codepen.io/collection/XmZoNW/">CS" Grid Layout Collection from Codepen</a></li> </ul> <h2>显示顺序 vs 文档顺序</h2> <p>在文章的最开始,我建议你以从上到下的阅读顺序来组织你的文档顺序,这样会有助于可读性和CSS的布局方式。从我们关于Flexbox和CSS Grid 布局的简短介绍来看,你可能发现用这些布局方法可能会极大地改变页面元素在文档中展示的顺序。这可能会导致一个隐含的问题。</p> <p>在一些非可视化的应用场景中,浏览器会遵循文档源码来进行使用。因此,屏幕阅读器会读取文档的顺序,此外使用键盘<code>tab</code>键来浏览的用户访问文档的顺序是基于源码的顺序,而不是元素展示的顺序。许多屏幕阅读器的用户并非完全失明,他们可能在使用屏幕阅读器的同时也能够看到这些元素在文档的哪个部分。在这些情况下,当与源码进行对比时,这种混乱的页面展现可能会令人充满迷惑。</p> <p>当你改变了元素在文档中原来的顺序时,一定确保知道自己在做什么。如果你发现你自己正在CSS中重新排序你的元素,你应该去回头看看是否要重新组织你的页面元素。你可以通过使用<code>tab</code>访问来测试一下你的页面。</p> <h3>扩展阅读</h3> <ul> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/CSS_Grid_Layout_and_Accessibility">CS" Grid Layout and Accessibility</a></li> <li><a href="//adrianroselli.com/2015/10/html-source-order-vs-css-display-order.html">HTML Source Order vs CSS Display Order</a></li> <li><a href="http://xxysy.com/quot;//tink.uk/flexbox-the-keyboard-navigation-disconnect/">Flexbo" And The Keyboard Navigation Disconnect</a></li> <li><a href="http://xxysy.com/quot;//alastairc.ac/2017/06/the-responsive-order-conflict/">Th" Responsive Order Conflict For Keyboard Focus</a></li> <li><a href="//webdesign.tutsplus.com/tutorials/a-few-different-css-methods-for-column-ordering--cms-27079">A Few Different CSS Methods for Changing Display Order</a></li> </ul> <h2>盒模型的生成</h2> <p>你写在网页里的任何东西都会生成一个盒子(HTML每一个元素都是个盒子),这篇文章讨论的所有东西其实都是如何能够使用CSS来按照你的设计布局这些盒子。然而,在某些情况下,你可能根本不想创建一个盒子。<code>display</code>属性有两个值会帮你处理这种情况。</p> <h3>不生成盒子或内容(display: none)</h3> <p>如果你希望元素以及它所有的内容(包括所有子元素)都不会生成,你可以使用<code>display: none</code>。这样元素就不会被展示,并且不会保留其本该占有的空间。</p> <pre><code>.item { display: none; } </code></pre> <h3>不生成该元素,但是生成其所有子元素(<code>display: contents</code>)</h3> <p><code>display: content</code>是<code>display</code>的一个新的属性值。为一个元素应用<code>display: content</code>属性会导致其自身的盒子不生成但所有的子元素都会照常生成。这有什么用呢?试想一下,如果你希望一个弹性布局或网格布局中的非直接子元素能应用这些布局,这就会非常有用。</p> <p>在下面这个例子里,第一个弹性项包含了两个子元素,由于它被设为<code>display: contents</code>,它的盒子不会生成并且它的两个子元素会成为弹性项,并被当作弹性盒子容器的直接子元素来布局。</p> <div style="margin-bottom: 20px;"><iframe id="XBbabE" src="//codepen.io/airen/embed/XBbabE?height=400&amp;theme-id=0&amp;slug-hash=XBbabE&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>扩展阅读</h3> <ul> <li><a href="http://xxysy.com/quot;//www.w3.org/TR/CSS2/box.html">Bo" model</a></li> <li><a href="//www.w3.org/TR/css-display-3/">CSS Display Module Level 3</a></li> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/why-display-contents-is-not-css-grid-layout-subgrid.html">为什么是display:contents而不是CSS Grid的subgrid</a></li> <li><a href="http://xxysy.com/quot;//rachelandrew.co.uk/archives/2016/01/29/vanishing-boxes-with-display-contents/">Vanishin" Boxes With display: contents</a></li> <li><a href="http://xxysy.com/quot;//bitsofco.de/how-display-contents-works/">Ho" display: contents; Works</a></li> </ul> <h2>对齐方式</h2> <p>直到现在,对齐在Web上一直是一个棘手的问题,并且能够使用的方法也非常有限。随着CSS盒模型对齐的出现,这一切都发生了变化。你将会使用它来控制Grid容器与Flexbox容器中的对齐。未来其他的各种布局方法都会应用这些对齐属性。盒模型对齐规范中的一系列详细属性如下:</p> <ul> <li><code>justify-content</code></li> <li><code>align-content</code></li> <li><code>place-content</code></li> <li><code>justify-items</code></li> <li><code>align-items</code></li> <li><code>place-items</code></li> <li><code>justify-self</code></li> <li><code>align-self</code></li> <li><code>place-self</code></li> <li><code>row-gap</code></li> <li><code>column-gap</code></li> <li><code>gap</code></li> </ul> <p>由于不同的布局模型有不同的特性,因此用于不同布局模型的对齐属性会有一些表现上的差异。让我们来看看在一些简单的网格与弹性布局中对齐是如何工作的。</p> <p><code>align-items</code>和<code>justify-items</code>属性相对是<code>align-self</code>和<code>justify-self</code>属性的一种批量形式。这些属性会控制与元素在其网格区域中的对齐情况。</p> <div style="margin-bottom: 20px;"><iframe id="OwVxjQ" src="//codepen.io/airen/embed/OwVxjQ?height=400&amp;theme-id=0&amp;slug-hash=OwVxjQ&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p><code>align-content</code>和<code>justify-content</code>属性则会对网格中的行或列进行对齐控制(网格容器中需要在排列完行或列元素后有多余的空间)。</p> <div style="margin-bottom: 20px;"><iframe id="ZjGXZY" src="//codepen.io/airen/embed/ZjGXZY?height=400&amp;theme-id=0&amp;slug-hash=ZjGXZY&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>在Flexbox 布局中,<code>align-items</code>和<code>align-self</code>用来解决交叉轴上的对齐问题,而<code>justify-content</code>则用于解决主轴上空间的分配。</p> <div style="margin-bottom: 20px;"><iframe id="oMXGRe" src="//codepen.io/airen/embed/oMXGRe?height=400&amp;theme-id=0&amp;slug-hash=oMXGRe&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>在交叉轴上,把弹性行(Flex Line)和额外空间包裹在Flexbox容器中之后,你就可以使用<code>align-content</code>了。</p> <div style="margin-bottom: 20px;"><iframe id="LBVOPj" src="//codepen.io/airen/embed/LBVOPj?height=400&amp;theme-id=0&amp;slug-hash=LBVOPj&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>下面的一些链接更细节地讨论了各类布局方法中的盒模型对齐。花些时间去理解对齐的工作原理是非常值得的,它对理解弹性盒子、网格布局以及未来的一些布局方法都会很有帮助。</p> <h3>行或列的间隔</h3> <p>一个多栏布局具有<code>column-gap</code>属性,到目前位置,网格布局具有<code>grid-column-gap</code>、<code>grid-row-gap</code>和<code>grid-grid</code>。这些现在都被从<code>grid</code>标准中删除而被添加进盒模型对齐中了。与此同时,<code>grid-</code>的前缀属性被重命名为<code>column-gap</code>、<code>row-gap</code>和<code>gap</code>。浏览器会将带有前缀的属性换为新的重命名属性,所以如果你在目前的代码中使用兼容性更好的老名字也不用担心。</p> <p>重命名意味着这些属性也能被应用于其他布局方法,一个明显的备选就是弹性盒子。虽然目前没有浏览器支持盒子模型中的<code>gap</code>属性,但是在未来我们应该可以使用<code>column-gap</code>和<code>row-gap</code>来创建弹性项目元素间的间距。</p> <h3>扩展阅读</h3> <ul> <li><a href="//www.w3.org/TR/css-align-3/">CSS Box Alignment Module Level 3</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Alignment">CS" Box Alignment</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Box_Alignment_in_Flexbox">Bo" Alignment in Flexbox</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Box_Alignment_in_CSS_Grid_Layout">Bo" Alignment in CSS Grid Layout</a></li> <li><a href="//www.smashingmagazine.com/2016/11/css-grids-flexbox-box-alignment-new-layout-standard/">The New Layout Standard For The Web: CSS Grid, Flexbox And Box Alignment</a></li> <li><a href="//rachelandrew.co.uk/css/cheatsheets/box-alignment">Box Alignment Cheatsheet</a></li> <li><a href="//rachelandrew.co.uk/archives/2015/09/02/css-grid-and-the-box-alignment-module/">CSS Grid and The Box Alignment Module</a></li> <li><a href="http://xxysy.com/quot;//24ways.org/2015/grid-flexbox-box-alignment-our-new-system-for-layout/">Grid" Flexbox, Box Alignment: Our New System for Layout</a></li> </ul> <h2>多列布局</h2> <p>多列布局是一种支持创建多列的布局类型,如同报纸上那样。每一块都被分割成列,你会按照块方向在列中往下读然后会在回到下一列的顶部。然而用这种方式阅读在网页内容中并不总是有效,因为人们并不想去让滚动条滚动来、滚动去地去阅读。当需要展示少部分内容、折叠一组复选框或者其他一些小的UI伟德1946手机版时会非常有用。</p> <p>当展示一组高度不同的卡片或产品时多列布局也非常有用。</p> <h3>设置列的宽度</h3> <p>要设置一个最优的列宽,并通知浏览器依此宽度展示尽可能多的列可以使用下面的CSS:</p> <pre><code>.container { column-width: 300px; } </code></pre> <p>这会创建尽可能多的<code>300px</code>宽的列,所有剩下的空间会被所有列共享。因此,除非空间被划分为<code>300px</code>时没有剩余,否则你的列会比<code>300px</code>稍多一些。</p> <h3>设置列的数目</h3> <p>除了设置宽度,你可以使用<code>column-count</code>来设置列的数目。在这种情况下,浏览器会将空间均分给你需要的数目的列。</p> <pre><code>.container { column-count: 3; } </code></pre> <p>如果你同时添加了<code>column-width</code>和<code>column-count</code>,那么<code>column-count</code>属性会作为一个最大值限制。在下面的代码里,列会被添加直到达到三个,此时任何额外的空间都会被分给三列,即使空间足够成为一个额外的新列。</p> <pre><code>.container { column-width: 300px; column-count: 3; } </code></pre> <h3>间距和列规则</h3> <p>你无法为单个列盒子添加<code>margin</code>和<code>padding</code>,需要用<code>column-gap</code>属性来设置间距。如果你不具体指定<code>column-gap</code>的值,它会默认为<code>1em</code>来防止列间碰撞。这和其他布局方法中<code>column-gap</code>的行为不一样,其他布局中默认为<code>0</code>。你可以在间距上使用任意的长度单元,包括<code>0</code>(如果你不希望有列间距)。</p> <p><code>column-rule</code>属性让你有能力向两列间添加规则。它是<code>column-rule-width</code>、<code>column-rule-color</code>和<code>column-rule-style</code>的简写形式,和<code>border</code>行为类似。注意,一个规则自身不会占用任何空间。它会占据在间距的顶部,从而增加或减少那些你设置<code>column-gap</code>的规则与内容间的空间。</p> <div style="margin-bottom: 20px;"><iframe id="rrVYKw" src="//codepen.io/airen/embed/rrVYKw?height=400&amp;theme-id=0&amp;slug-hash=rrVYKw&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>允许元素横跨多列</h3> <p>你可以使用<code>column-span</code>属性让多列容器内的元素横跨多列,类似通列。</p> <pre><code>h3 { column-span: all; } </code></pre> <p>当<code>column-span</code>出现时,多列容器分列会在这个元素上停止,因此,容器里的内容会在元素上方形成多列样式,然后在横跨元素的下方形成一组新的列盒子(Column Box)。</p> <div style="margin-bottom: 20px;"><iframe id="zLGPyP" src="//codepen.io/airen/embed/zLGPyP?height=400&amp;theme-id=0&amp;slug-hash=zLGPyP&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>你只可以使用<code>column-span: all</code>或<code>column-span: none</code>,并不能让元素横跨某几个列(非通列)。在文章写作时,Firefox还不支持<code>column-span</code>属性。</p> <h3>扩展阅读</h3> <ul> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/CSS/CSS_Columns/Using_multi-column_layouts">Usin" Multi-Column Layouts</a></li> <li><a href="//www.w3.org/TR/css-multicol-1/">CSS Multi-column Layout Module Level 1</a></li> </ul> <h2>碎片化</h2> <p>多列布局是碎片化的一个例子,页面内容会被拆分成列。这和打印时内容被分到不同页非常类似。这个过程是碎片化规范(Fragmentation specification)处理的。这个规范包括了一些帮助控制内容切分的属性。</p> <p>例如,如果你有一组置于多列中的卡片,并且你想确保卡片不会被截为两半分到不同的列,你可以使用<code>break-inside</code>属性的<code>avoid</code>值。考虑浏览器兼容性的因素,你也可能会想使用遗留的<code>page-break-inside</code>属性。</p> <pre><code>.card { page-break-inside: avoid; break-inside: avoid; } </code></pre> <p>如果你想在标题元素后禁止断行,你可以使用<code>break-after</code>属性。</p> <pre><code>.container h2 { page-break-after: avoid; break-after: avoid; } </code></pre> <p>这些属性可以被用在打印样式或多列样式中。在下面的例子里,在多列容器中的三个段落被拆分到了三列之中。我为<code>p</code>元素设置了<code>break-inside: avoid</code>,这意味着每个多列会在自己的列中结束(即使这会使各列长度不同)。</p> <div style="margin-bottom: 20px;"><iframe id="rrVpVJ" src="//codepen.io/airen/embed/rrVpVJ?height=400&amp;theme-id=0&amp;slug-hash=rrVpVJ&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>扩展阅读</h3> <ul> <li><a href="http://xxysy.com/quot;//www.smashingmagazine.com/2018/05/print-stylesheets-in-2018/">" Guide To The State Of Print Stylesheets In 2018</a></li> <li><a href="//www.quirksmode.org/css/columns/breaks.html">Column Breaks</a></li> <li><a href="//www.w3.org/TR/css-break-3/">CSS Fragmentation Module Level 3</a></li> </ul> <h2>如何选择布局类型?</h2> <p>大多数的网页会混合使用多种布局类型。各布局规范都准确定义了它们之间是如何相互作用的。例如,你可能会在网格布局的网格项中使用弹性布局。一些弹性容器可能具有定位属性或浮动。这些规范根据最优的布局方式已经包含了布局模型的混合使用。在这篇指南中,我尝试概述了这种布局类型的基本使用方式,来帮助你了解实现一个效果可能的最好方法。</p> <p>然而,别害怕去运用多种方式来实现布局设计。担心你的选择会不会造成实际问题的情况比你想象中要少很多。所以请在开始就组织好你的文档结构,并且注意你文档内容的可视展示顺序。剩下的大部分工作就是在浏览器中试试你的布局方式是否符合预期。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/guide-css-layout.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/guide-css-layout.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/translations"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">译文</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/68.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/180.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Layout</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/130.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">布局</a></div></div></div> Thu, 12 Jul 2018 14:56:56 +0000 Airen 2429 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/DOM-manipulation-tutorial-series.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>DOM是JavaScript的基础之一,自己学习DOM的操作也有一段时间了,到今天为止<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/663.html">DOM系列的伟德1946网页版</a>刚好有十篇了,这部分都主要是围绕DOM操作的笔记。主要围绕DOM元素的增、删、改、查,DOM节点的操作以及元素尺寸、位置获取和设置等知识。今天这篇文章主要是小结一下。希望对一些像我这样的初学者有所帮助。</p>" <h2><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/browser-and-the-dom.html">浏览器与DOM</a></h2> <p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/browser-and-the-dom.html"><img src="/sites/default/files/blogs/2018/1805/browser-dom-1.png" alt="浏览器与DOM" /></a></p> <p>这篇文章只是了解了DOM中最简单,最基础的一部分。实际上,使用它的功能与你的Web文档交互是更大更有趣的部分。不过这将是后面要了解的东西,因为在深入探讨这部分之前,我们需要先了解DOM的一些基础和概念,只有这样才能发挥DOM的强大优势,更好的帮助我们操作Web页面或者说Web应用程序。</p> <h2><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-tree-and-traversals.html">DOM树和遍历DOM</a></h2> <p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-tree-and-traversals.html"><img src="/sites/default/files/blogs/2018/1805/dom-tree-1.jpeg" alt="DOM树和遍历DOM" /></a></p> <p>这篇文章主要介绍了DOM树和DOM的遍历。前一部分只要介绍了DOM树,简单的理解,任何一个HTML文档都可以类似于家族的族普来绘制对应的DOM树。通过DOM树可以理清楚每个DOM元素(或者说DOM节点)之间的关系。比如,父子关系、兄弟关系等。</p> <h2><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/searching-elements-dom.html"><code>getElement*</code> 和 <code>querySelector*</code></a></h2> <p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/searching-elements-dom.html"><img src="/sites/default/files/blogs/2018/1807/getElementById_vs_querySelector.png" alt="" /></a></p> <p>选择DOM中的元素,除了一些节点属性之外,还有一些API可以帮助我们获取DOM元素,比如在这篇文章介绍的<code>getElement*</code>和<code>querySelector*</code>:</p> <ul> <li><code>getElementById()</code></li> <li><code>getElementsByClassName()</code></li> <li><code>getElementsByTagName()</code></li> <li><code>getElementsByName()</code></li> <li><code>document.querySelector()</code></li> <li><code>document.querySelectorAll()</code></li> </ul> <p>这其实就是DOM增删改查中的<strong>查</strong>。从划分上可以看出来,简单的可以理解查找DOM元素API的两个系列。而这篇文章主要介绍的就是他们之间的差异。</p> <h2><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/663.html">DOM节点属性</a></h2>" <p><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/663.html"><im" src="/sites/default/files/blogs/2018/1805/dom-node-properties-1.png" alt="DOM节点属性" /></a></p> <p>每个DOM节点属于某个类。这些类构成一个DOM树。所有的属性和方法都将被继承。这篇文章就是围绕DOM节点属性展开的,主要阐述了DOM节点类、DOM节点类型、DOM节点标签、DOM节点内容四个部分。主要的DOM节点属性有:<code>nodeType</code>、<code>nodeName</code>、<code>tagName</code>、<code>innerHTML</code>、<code>outerHTML</code>、<code>nodeValue</code>、<code>textContent</code>等。</p> <h2><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-attributes-and-properties.html">Attribute和Property</a></h2> <p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-attributes-and-properties.html"><img src="/sites/default/files/blogs/2018/1805/dom-attributes-properties-6.png" alt="Attribute和Property" /></a></p> <p>这两天一直在看DOM元素的attribute和property,简单让人晕。从直译上,我一开始都理解为“属性”,而且对于我这样的新手,将两者混淆在一起,傻傻的分不清楚。后来经过大大们的指点,知道两者是不同的东西,但两者之间又有紧密的联系。这篇文章有利于初学者能更清晰的整明白两者的关系与不同。</p> <h2><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/modifying-document.html">修改DOM</a></h2> <p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/modifying-document.html"><img src="/sites/default/files/blogs/2018/1805/modify-dom-4.png" alt="修改DOM" /></a></p> <p>这篇文章主要学习了如何修改DOM。涉及到的内容也比较多,简单的做一下小总结。</p> <ul> <li>创建新节点的方法:<code>document.createElement(tag)</code>、<code>document.createTextNode(value)</code>和<code>elem.cloneNode(deep)</code></li> <li>插入和删除节点的DOM API:<code>parent.appendChild(node)</code>、<code>parent.insertBefore(node, nextSibling)</code>、<code>parent.removeChild(node)</code>和<code>parent.replaceChild(newElem, node)</code></li> <li>给定一个节点和字符串的相关操作:<code>node.append(...nodes or strings)</code>、<code>node.prepend(...nodes or strings)</code>、<code>node.before(...nodes or strings)</code>、<code>node.after(...nodes or strings)</code>、<code>node.replaceWith(...nodes or strings)</code>和<code>node.remove()</code></li> <li>指定HTML片段插入的位置:<code>beforebegin</code>、<code>afterbegin</code>、<code>beforeend</code>和<code>afterend</code></li> </ul> <h2><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/style-and-class.html">样式和类</a></h2> <p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/style-and-class.html"><img src="/sites/default/files/blogs/2018/1807/Lesson-32DOM-Adding-Removing-Toggling-CSS-Classes-using-JavaScript.png" alt="样式和类" /></a></p> <p>这篇文章主要介绍了如何通过JavaScript来修改CSS样式。我们平常中会使用到的方法会有:</p> <ul> <li>通过DOM Element对象的<code>getAttribute()</code>、<code>setAttribute()</code>和<code>removeAttribute()</code>等方法修改元素的<code>style</code>属性</li> <li>通过对元素节点的<code>style</code>来读写行内CSS样式</li> <li>通过<code>style</code>对象的<code>cssText</code>属性来修改全部的<code>style</code>属性</li> <li>通过<code>style</code>对象的<code>setProperty()</code>、<code>getPropertyValue()</code>、<code>removeProperty()</code>等方法来读写行内CSS样式</li> <li>通过<code>window.getComputedStyle()</code>方法获得浏览器最终计算的样式规则</li> <li>通过<code>className</code>或<code>classList</code>给元素添加或删除类名,配合样式文件来修改元素样式</li> </ul> <h2><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/add-rules-stylesheets.html">动态添加CSS样式规则</a></h2> <p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/add-rules-stylesheets.html"><img src="/sites/default/files/blogs/2018/1806/dom-css-1.png" alt="动态添加CSS样式规则" /></a></p> <p>事实上我们还可以通过脚本化CSS这种技术来控制样式。这种方式,可以让我们的页面更加的快速和高效。那就是直接通过JavaScript动态地添加和删除样式表中的某些样式,用来取代不断地查询DOM元素,并应用各种样式。</p> <h2><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/get-element-position-and-size-using-javascript.html">获取元素位置和尺寸</a></h2> <p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/get-element-position-and-size-using-javascript.html"><img src="/sites/default/files/blogs/2017/1711/window-scroll-14.png" alt="获取元素位置和尺寸" /></a></p> <p>JavaScript检测元素有六个DOM的几何结构属性:<code>offsetWidth</code>、<code>offsetHeight</code>、<code>clientWidth</code>、<code>clientHeight</code>、<code>scrollWidth</code>、<code>scrollHeight</code>。再加上<code>offsetTop</code>、<code>offsetLeft</code>、<code>scrollTop</code>、<code>scrollLeft</code>、<code>clientTop</code>和<code>clientLeft</code>等方向距离的属性。这样一来,让事情就变得复杂,对于像我这样的初学者而言,极难理解,也易产生一些错误。正因这个原因,整理了一篇这样的文章。</p> <h2><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/viewport-device-scroll-document-size.html">视窗、设备、滚动条和文档尺寸</a></h2> <p><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/viewport-device-scroll-document-size.html"><img src="/sites/default/files/blogs/2018/1807/5a9df53e025be.jpg" alt="视窗、设备、滚动条和文档尺寸" /></a></p> <p>这篇文章将学习视窗、设备、滚动条和文档等相关的尺寸。其实在前两篇文章中都有涉及这些知识,为了让DOM系列相关的知识更完善。</p> <h2>总结</h2> <p>这篇文章是DOM系列中的一个小总结,也是一个小集合。主要涉及DOM中的操作,围绕DOM元素、DOM节点和DOM属性的增、删、改、查的操作。另外一部分围绕DOM元素的样式的控制和DOM元素的尺寸位置相关的操作。但这些并没有涉及到DOM事件的操作。</p> <p>仅仅掌握上面的这些内容还不足够让我们掌握DOM的。在JavaScript中有关于DOM相关的知识,还有DOM事件是必须要掌握。所以接下来一段时间,将会围绕DOM事件学习。如果你感兴趣的话,欢迎持续关注这个系列的学习。</p> <p>由于自己也是JavaScript的初学者,文章难免有错误之处,烦请各位大婶拍正。更欢迎有这方面的相关经验的同学,在下面的评论中与我一起分享。如果你觉得这个系列有助于你学习和成长,欢迎各位大爷打个赏,我将持续创作更多有质量的伟德1946网页版。(^_^)!</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/DOM-manipulation-tutorial-series.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/DOM-manipulation-tutorial-series.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/660.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/663.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM系列</a></div></div></div> Mon, 09 Jul 2018 13:59:45 +0000 Airen 2428 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/css-custom-properties-strategy-guide.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>特别声明,本文根据<a href="http://xxysy.com/quot;//www.smashingmagazine.com/author/michaelriethmuller/">@Michae" Riethmuller</a>的《<a href="//www.smashingmagazine.com/2018/05/css-custom-properties-strategy-guide">A Strategy Guide To CSS Custom Properties</a>》一文所整理。</p> </blockquote> <p><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/601.html">CSS自定义属性</a>有很大的潜力可以改变我们编写和组" CSS 的方式,并且在一定程度上改变 JavaScript 与 UI 伟德1946手机版的调用方式。我并不关心语法和它们的工作方式(为此,我建议你阅读“《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/start-using-css-custom-properties.html">是时候开始使用自定义属性</a>》这篇文章。同时我想更深入地研究如何充分使用 CSS 自定义属性。</p> <h2>自定义属性与预处理器中的变量有何相似之处?</h2> <p>CSS自定义属性有点像预处理器中的变量,但还是有很大的差别。最重要也是最明显的区别是语法上。</p> <p>在 SCSS 中我们用 <code>$</code> 符号来定义变量:</p> <pre><code>$smashing-red: #d33a2c; </code></pre> <p>在 Less 中我们用 <code>@</code>符号:</p> <pre><code>@smashing-red: #d33a2c; </code></pre> <p>CSS自定义属性遵循类似的约定并使用 <code>--</code> 前缀的方式:</p> <pre><code>:root { --smashing-red: #d33a2c; } .smashing-text { color: var(--smashing-red); } </code></pre> <p>CSS自定义属性和预处理器中的变量最大的不同在于"键值对"的语法规则。自定义属性采用 <code>var()</code> 函数去取值。</p> <p>另一个明显的区别是名称。它们之所以被称为"自定义属性",是因为它们是纯粹的 CSS 属性。在预处理器中,你可以在任何位置声明和使用变量,包括外部声明块,在媒体查询中,甚至在选择器中也可以使用,例如:</p> <pre><code>$breakpoint: 800px; $smashing-red: #d33a2c; $smashing-things: ".smashing-text, .cats"; @media screen and (min-width: $breakpoint) { #{$smashing-things} { color: $smashing-red; } } </code></pre> <p>而使用自定义属性,上面的大多数示例都是无效的。</p> <p>自定义属性和常规 CSS 属性的用法是一样的。把它们当作动态属性会比变量更好。这意味着它们只能在声明块中使用,换句话说,自定义属性和选择器是强绑定的。这可以是 <code>:root</code> 选择器或任何其它有效的选择器。</p> <pre><code>:root { --smashing-red: #d33a2c; } @media screen and (min-width: 800px) { .smashing-text, .cats { --margin-left: 1em; } } </code></pre> <p>你可以在属性声明中的任何地方获取变量声明的值,这个意味着它们可以作为单个值使用,作为一个简写语句的一部分,甚至是在 <code>calc()</code> 函数中使用。</p> <pre><code>.smashing-text, .cats { color: var(--smashing-red); margin: 0 var(--margin-horizontal); padding: calc(var(--margin-horizontal) / 2) } </code></pre> <p>但是,它们不能用于媒体查询或选择器,包括 <code>:nth-child()</code>。</p> <p>关于语法和自定义属性的工作原理可能还有很多,比如如何使用 <code>fallback</code> 值,以及我们还可以将变量分配给其他变量,本文介绍的基础知识应该已经足以让大家理解其中的概念。更多关于自定义属性工作方式的详细信息,可以阅读由 @Serg Hospodarets 的《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/start-using-css-custom-properties.html">是时候开始使用自定义属性</a>》。</p> <h2>动态变量 vs 静态变量</h2> <p>抛开样式差异,预处理器中的变量和自定义属性之间最大的差别就是作用域。我们可以将变量根据作用域分为静态变量和动态变量两个部分。预处理器中的变量是静态的,而自定义属性是动态的。</p> <p>在 CSS 中,静态意味着你可以在编译过程中更新变量的值,但是这不能改变它之前的值。</p> <pre><code>$background: blue; .blue { background: $background; } $background: red; .red { background: $background; } </code></pre> <p>结果是:</p> <pre><code>.blue { background: blue; } .red { background: red; } </code></pre> <p>一旦编译成了 CSS,这个变量就会消失。这意味着我们在读取一个 <code>.scss</code> 文件并输出的时候并不需要关心 HTML、浏览器或其它输入,而自定义属性并非如此。</p> <p>预处理器确实有一种“块级作用域”,其中变量可以在选择器,函数或 <code>mixin</code> 中临时更改。这改变了块内变量的值,但它仍然是静态的。这与块有关,而不是选择器。在下面的例子中,变量 <code>$background</code> 在 <code>.example</code> 类内部被改变。即使我们使用相同的选择器,它也会变回块级作用域之外的初始值。</p> <pre><code>$background: red; .example { $background: blue; background: $background; } .example { background: $background; } </code></pre> <p>编译后:</p> <pre><code>.example { background: blue; } .example { background: red; } </code></pre> <p>自定义属性不同于预处理器。在涉及自定义属性的地方,动态范围意味着它们受到继承和级联的影响。属性与选择器绑定,如果值发生变化,就会像其他 CSS 属性一样影响所有匹配的 DOM 元素。</p> <p>这听起来很赞,因为你可以在媒体查询中,通过使用类似 <code>hover</code> 的伪类选择器甚至是 JavaScript 改变自定义属性的值。</p> <pre><code>a { --link-color: black; } a:hover, a:focus { --link-color: tomato; } @media screen and (min-width: 600px) { a { --link-color: blue; } } a { color: var(--link-color); } </code></pre> <p>我们不需要在自定义属性使用的地方去修改它,我们可以通过 CSS 去修改它的值。这意味着同一个自定义属性,可以在不同的地方,或者是上下文中有不同的值。</p> <h2>全局变量 vs 局部变量</h2> <p>除了静态变量和动态变量之外,变量还可以是全局的或局部的。如果你经常写 JavaScript,你可能会更了解这一点。变量既可以作用在应用程序全局环境中,也可以将其作用域限制在特定的函数或代码块中。</p> <p>CSS 也一样。有全局的变量,也有局部的变量。品牌颜色、垂直间距、排版方式,这些你可能希望都在 APP 端和网页中全局调用。当然也有一些局部的东西,比如,按钮伟德1946手机版可能具有大小尺寸。你不希望这些按钮的大小适用于所有输入元素或页面上的每个元素。</p> <p>这是我们在 CSS 中熟悉的应用场景。我们开发了设计系统、命名规范和 JavaScript 库,这些可以分离局部伟德1946手机版和全局伟德1946手机版。自定义属性给这类问题提供了新的思路。</p> <p>通常 CSS 自定义属性的范围局限于我们指定的选择器中。这看起来有点像局部变量。但是,自定义属性具有继承的特性,所以在大多数情况下,它们表现的更像全局变量 —— 特别是在应用于 <code>:root</code> 选择器的时候。这意味着我们需要考虑如何使用它们。</p> <p>大量的示例都表示将自定义属性应用到 <code>:root</code> 元素上,对于 Demo 这还说得过去,但它可能会污染全局作用域,从而导致意外的继承问题。幸运的是,我们已经吸取了教训。</p> <h3>全局变量趋于静态</h3> <p>可能会有一些例外,但通常来说,CSS 中的大多数的全局变量也是静态的。</p> <p>比如品牌颜色、字体和间距之类的变量不会在不同的伟德1946手机版之间产生太大的变化。当它们发生变化时,这往往是一个全局性的品牌重塑,或者是在一个成熟产品上很少发生的其他重大变化。对于这些变量来说它们仍然是有意义的,它们在很多地方被使用,而变量有助于保持一致性。但让它们成为动态变量是没有意义的。这些变量的值不会以任何动态的方式变化。</p> <p>因此,我强烈建议<strong>对全局(静态)变量使用预处理器</strong>。这不仅确保了它们始终是静态的,而且还可以在代码中显得更直观。这可以使 CSS 更易于阅读和维护。</p> <h3>局部静态变量也尽量少用</h3> <p>你可能会认为,全局变量是趋于静态的,那么相反的,可能所有的局部变量都应该是动态的,但其实远不如全局变量是静态的开发起来更方便。</p> <p>而局部静态变量在很多情况下是动态的,是因为我在伟德1946手机版文件中使用预处理器变量,也主要是为了开发的方便。</p> <p><img src="/sites/default/files/blogs/2018/1807/buttons-small-medium-large.png" alt="" /></p> <p>我的 SCSS 可能看起来像这样:</p> <pre><code>$button-sml: 1em; $button-med: 1.5em; $button-lrg: 2em; .btn { // Visual styles } .btn-sml { font-size: $button-sml; } .btn-med { font-size: $button-med; } .btn-lrg { font-size: $button-lrg; } </code></pre> <p>显然,如果我多次使用变量或从变量计算得到 <code>margin</code> 或 <code>padding</code> 值,这个示例将更有意义。然而,快速原型化不同尺寸的能力可能是一个充分的理由。</p> <p>因为大多数静态变量都是全局的,所以我喜欢区分只在伟德1946手机版内部使用的静态变量。为此,可以在这些变量前面加上伟德1946手机版名,或者可以使用另一个前缀,如伟德1946手机版的 <code>c</code> 变量名或 <code>l</code> 变量名。您可以使用任何您想要的前缀,或者可以在全局变量前面加上前缀。无论您选择什么,区分都是很有帮助的,特别是当转换一个现有的代码来使用自定义属性时。</p> <h2>何时使用自定义属性</h2> <p>如果可以在伟德1946手机版内部使用静态变量,那么什么时候应该使用自定义属性呢? 将现有的预处理器变量转换为自定义属性通常没什么意义。毕竟,自定义属性的用途是完全不同的。当我们有 CSS 属性时,自定义属性是有意义的,尤其是在 DOM 中(尤其是动态条件),例如 <code>:fouces</code>、<code>hover</code>、媒体查询或 JavaScript。</p> <p>我猜想我们将始终使用某种形式的静态变量,尽管我们将来可能需要更少的静态变量,因为自定义属性提供了组织逻辑和代码的新方法。在此之前,我认为在大多数情况下,我们可以将预处理器变量和自定义属性组合使用。</p> <p>我们可以为自定义属性分配静态变量。无论它们是全局的还是局部的,在许多情况下,将静态变量转换为局部动态自定义属性都是有意义的。</p> <blockquote> <p>注意:您知道 <code>$var</code> 是自定义属性的有效值吗? Sass 的最新版本认识到了这一点,因此我们需要插入分配给自定义属性的变量,如: <code>#{$var}</code>。这告诉 Sass 您希望输出变量的值,而不是样式表中的 <code>$var</code>。这只适用于自定义属性等情况,其中变量名也可以是有效的 CSS。</p> </blockquote> <p>如果我们以上面的按钮示例为例,决定所有的按钮都应该使用移动设备上的小变化,而不考虑 HTML 中应用的类,这是一种更动态的情况。为此,我们应该使用自定义属性。</p> <pre><code>$button-sml: 1em; $button-med: 1.5em; $button-lrg: 2em; .btn { --button-size: #{$button-sml}; } @media screen and (min-width: 600px) { .btn-med { --button-size: #{$button-med}; } .btn-lrg { --button-size: #{$button-lrg}; } } .btn { font-size: var(--button-size); } </code></pre> <p>这里,我创建了一个自定义属性: <code>--button-size</code>。这个自定义属性最初的作用域是使用 <code>btn</code> 类的所有按钮元素。然后,我将 <code>btn-med</code> 和 <code>btn-lrg</code> 类的按钮大小更改为 <code>600px</code> 以上。最后,我将这个自定义属性应用到一个位置的所有按钮元素。</p> <h2>不要聪明过头</h2> <p>自定义属性的动态特性允许我们创建一些聪明而复杂的伟德1946手机版。</p> <p>随着预处理器的推出,我们中的许多人可以使用 <code>mixin</code> 和自定义函数创建具有巧妙抽象的库。在有限的情况下,像这样的例子仍然有用,但大多数情况下,随着使用预处理器的时间越长,我使用的功能就越少。现在,我使用预处理器的场景几乎只在静态变量的部分。</p> <p>自定义属性同样也会出现这样的状况,我期待看到更多聪明的例子。但从长远来看,可读和可维护的代码总会是更好的选择(至少在项目中是这样)。</p> <p>我最近在 Free Code Camp Medium 上阅读了关于此主题的优秀文章。它是由 @Bill Sourour 撰写的,叫《<a href="http://xxysy.com/quot;//medium.freecodecamp.org/dont-do-it-at-runtime-do-it-at-design-time-c4f59d1775e4">Don’" Do It At Runtime. Do It At Design Time</a>》。与其解释他的观点,我更推荐你先去看一下这篇文章。</p> <p>预处理变量和自定义属性之间的一个关键区别是:<strong>自定义属性在运行时工作</strong>。这意味着,在复杂性方面自定义属性是可以被接受的,因为预处理器没有自定义属性这么好的办法。</p> <p>最近我常用来举例说明的一个例子是:</p> <pre><code>:root { --font-scale: 1.2; --font-size-1: calc(var(--font-scale) * var(--font-size-2)); --font-size-2: calc(var(--font-scale) * var(--font-size-3)); --font-size-3: calc(var(--font-scale) * var(--font-size-4)); --font-size-4: 1rem; } </code></pre> <p>这产生了一个比例伟德1946手机版。比例伟德1946手机版是一系列和比率相互关联的数字。它们经常用于网页设计和开发来设置字体大小或间距。</p> <p>在本例中,每个自定义属性都是使用 <code>calc()</code> 确定的,方法是取之前的自定义属性的值并将其乘以比率。这样做,我们可以得到下一个数字。</p> <p>这意味着在运行时计算比率,您可以通过只更新 <code>--font-size</code> 属性的值来更改它们。例如:</p> <pre><code>@media screen and (min-width: 800px) { :root { --font-scale: 1.33; } } </code></pre> <p>如果你想改变比例,这比再次计算所有的值要聪明、简洁和快得多。这也是我在开发过程中不会做的事情。</p> <p>虽然上面的例子对于原型设计很有用,但在开发中我更喜欢看到类似这样的东西:</p> <pre><code>:root { --font-size-1: 1.728rem; --font-size-2: 1.44rem; --font-size-3: 1.2em; --font-size-4: 1em; } @media screen and (min-width: 800px) { :root { --font-size-1: 2.369rem; --font-size-2: 1.777rem; --font-size-3: 1.333rem; --font-size-4: 1rem; } } </code></pre> <p>与 @Bill 的文章中的例子类似,我发现查看实际值的含义很有帮助。我们阅读代码的次数比我们编写的次数多得多,而且字体等全局参数在项目中很少变化。</p> <p>上面的例子还不算完美。它违反了以前的规则,即<strong>全局变量应该是静态的</strong>。我更愿意使用预处理器变量,并使用前面演示的例子将它们转换为局部动态自定义属性。</p> <p>避免使用一个自定义属性到另一个自定义属性的情况也很重要。当我们命名这样的属性时,会发生这种情况。</p> <h2>修改属性值而不是变量</h2> <p>这是使用自定义属性的最重要准则之一。</p> <p>通常来说,不推荐修改仅有单一目的的自定义属性。虽然这很容易实现,因为这正是预处理器应该做的事情,但对于自定义属性来说这没有多大意义。</p> <p>在这个例子中,示例伟德1946手机版上我们创建了两个使用的自定义属性。根据屏幕的尺寸变化,将自定义属性 <code>--font-size-small</code> 修改为 <code>--font-size-large</code>。</p> <pre><code>:root { --font-size-small: 1.2em; --font-size-large: 2em; } .example { font-size: var(--font-size-small); } @media screen and (min-width: 800px) { .example { font-size: var(--font-size-large); } } </code></pre> <p>更好的方式是在这个组建当中只定义一个自定义属性,然后通过媒体查询或者其它的选择器改变这个属性的值。</p> <pre><code>.example { --example-font-size: 1.2em; } @media screen and (min-width: 800px) { .example { --example-font-size: 2em; } } </code></pre> <p>最后,只通过调用这个自定义属性来获取你想要的属性值。</p> <pre><code>.example { font-size: var(--example-font-size); } </code></pre> <p>在这个和之前的例子中,我们都仅通过使用媒体查询去修改自定义属性的值。也只在一个地方通过 <code>var()</code>去声明这个自定义属性,然后 CSS 的值就通过这个自定义属性自动更新了。</p> <p>我们故意分离了值声明和属性声明,这样做的原因其实有很多,响应性设计就是一个最明显的例子。</p> <h2>使用自定义属性创建响应布局</h2> <p>响应式布局中最大的难点在于它太过于依赖媒体查询,这导致无论你多么用心的管理你的 CSS,和伟德1946手机版相关的样式都会变得很零散。</p> <p>你很难知道哪些 CSS 属性会发生改变。CSS 自定义属性,正好可以帮助我们处理与响应式设计相关的这个逻辑关系,从而降低媒体查询的使用难度。</p> <h3>如果它改变了,这仅仅只是一个变量而已</h3> <p>媒体查询中属性的变化本身就是动态的,自定义属性正好弥补了 CSS 属性不具有动态性的特点。这意味着如果你想通过媒体查询来修改 CSS 属性,自定义属性是一个不错的选择。</p> <p>然后,你可以将媒体查询规则、<code>hover</code> 的状态或者任何定义了属性值修改方式的动态选择器,都移动到文档的顶部。</p> <h3>将逻辑和设计分离</h3> <p>如果你的操作正确,那么逻辑与设计的分离意味着媒体查询只是用来改变自定义属性的值。而这说明与响应性设计相关的所有逻辑都应该放到于文档的顶部,并且无论我们在哪里看到 <code>var()</code> 声明语句,我们都能很明显的知道这个属性会发生变化。而使用传统的 CSS 方式,我们是无法察觉这一点的。</p> <p>我们中的大多数人都非常擅长阅读和理解 CSS,我们需要思考在不同的状态下哪些属性发生了变化。我受够这样的方式了。现在自定义属性帮我们把逻辑和实现链接了起来,所以我们不需要在大脑去跟踪这些变化,这在项目中真的非常有用!</p> <h3>折叠逻辑</h3> <p>在文档或函数顶部声明变量的想法是很早就有的方式。也是大多数语言中推荐的做法,现在我们也可以在 CSS 中完成。以这种方式编写 CSS,光从视觉角度就很容易区分顶部和之后的代码。我要使用它们时我能很方便的找到它们。而这就是我强调的“折叠逻辑”的概念。</p> <p>在这个折叠的上方包含所有预处理器变量和自定义属性。这包含了所有的参数和自定义属性可能的变化。这样我们就很容易的知道自定义属性发生了哪些变化。</p> <p>在这段折叠之后的 CSS 代码可读性也是很高的,这就和你原来写媒体查询,和其它必要的代码一样没有什么区别。</p> <p>我们再来看一个关于六列 Flexbox 布局的网格系统非常简单的例子:</p> <pre><code>.row { --row-display: block; } @media screen and (min-width: 600px) { .row { --row-display: flex; } } </code></pre> <p>这个 <code>--row-display</code> 自定义属性的初始值设置为 <code>block</code>。当屏幕超过 <code>600px</code> 之后这个值会被重置为 <code>flex</code>。</p> <p>在折叠区域下面的代码可能看起来像这样:</p> <pre><code>.row { display: var(--row-display); flex-direction: row; flex-wrap: nowrap; } .col-1, .col-2, .col-3, .col-4, .col-5, .col-6 { flex-grow: 0; flex-shrink: 0; } .col-1 { flex-basis: 16.66%; } .col-2 { flex-basis: 33.33%; } .col-3 { flex-basis: 50%; } .col-4 { flex-basis: 66.66%; } .col-5 { flex-basis: 83.33%; } .col-6 { flex-basis: 100%; } </code></pre> <p>我们可以很直观的知道 <code>--row-display</code> 是一个变量。并且它的值现在应该是 <code>block</code>,而不是 <code>flex</code>。</p> <p>这是一个简单的例子,但如果我们要拓展一个填充剩余空间列的话,<code>flex-grow</code>、<code>flex-shrink</code> 和 <code>flex-basis</code> 值则同样需要转换为自定义属性。你可以尝试写一下,或者点击这里看一下<a href="http://xxysy.com/quot;//codepen.io/MadeByMike/pen/f42ce1a954af9796ae76c62a9ea801f4">更详细的例子</a>。</p>" <h2>基于主题创建自定义属性</h2> <p>我不推荐使用自定义属性去创建全局动态变量,也不推荐将自定义属性附加到 <code>:root</code> 选择器作用域下。但是每个规则都有一个例外,对于自定义属性而言,在创建主题的场景下,这就是一个例外。</p> <p>有节制的使用全局自定义属性可以使主题的创建更容易。</p> <p>主题化通常指的是让用户以某种方式定制UI。这可能类似于在配置文件上修改颜色。更简单的说,就像你在 Google Keep 这个应用程序中为你的笔记选择了一个颜色一样。</p> <p><img src="/sites/default/files/blogs/2018/1807/google-keep-app.png" alt="" /></p> <p>主题化通常会有独立的样式表用与基于用户的选择来覆盖之前的样式,或者对于不同的样式有完全独立的样式表文件。这两种方法实现都比较困难,并且会对性能产生影响。</p> <p>使用自定义属性,我们不需要编译不同的样式表;我们只需要根据用户的喜好更新属性的值。由于它们是继承的值,如果我们在根元素上声明自定义属性,它们可以在应用程序的任何地方使用。</p> <h3>用全大写的方式表示全局动态属性</h3> <p>自定义属性对大小写是敏感的,自定义属性建议都是局部的,如果你需要使用到是全局动态属性,推荐使用全大写的方式。</p> <pre><code>:root { --THEME-COLOR: var(--user-theme-color, #d33a2c); } </code></pre> <p>全大写的变量常常用于表示全局常量。对我们来说,一看到全大写的变量,则这意味着该属性是全局的,我们不应该在局部去修改它。</p> <h3>避免直接设置全局动态属性</h3> <p>自定义属性能接受一个备选值。我们应该避免直接覆盖全局自定义属性的值并尽量与其它值分离。我们可以使用备选值来实现这一点。</p> <p>上个例子我们有将 <code>--THEME-COLOR</code> 的值设置为 <code>--user-theme-color</code>。如果 <code>--user-theme-color</code> 未设置,则将使用备选值 <code>#d33a2c</code>。这样,我们无需在每次使用 <code>--THEME-COLOR</code> 时都提供一个备选值。</p> <p>在下面的例子中你可能希望的是背景被设置为 <code>green</code>。但是在 <code>:root</code> 作用域下的 <code>--user-theme-color</code> 的值并没有设置,所以最后 <code>--THEME-COOR</code> 值不会发生变化。</p> <pre><code>:root { --THEME-COLOR: var(--user-theme-color, #d33a2c); } body { --user-theme-color: green; background: var(--THEME-COLOR); } </code></pre> <p>像这样间接设置全局动态属性可以防止它们在局部被覆盖,并确保用户的设置始终都从根元素继承。这个约定能避免主题参数被意外的继承。</p> <p>如果我们想要将某些特定的属性暴露出去,我们可以用 <code>*</code> 号选择器替换 <code>:root</code> 选择器:</p> <pre><code>* { --THEME-COLOR: var(--user-theme-color, #d33a2c); } body { --user-theme-color: green; background: var(--THEME-COLOR); } </code></pre> <p>现在 <code>--THEME-COLOR</code> 在每个元素中的值都会重新计算,因此可以使用 <code>--user-theme-color</code> 这个局部变量。换句话说,这个例子中的背景颜色是 <code>green</code>。</p> <p>你可以在 使用自定义属性控制颜色一节中看到更多详细示例。</p> <h3>使用 JavaScript 更新自定义属性</h3> <p>如果你想通过 JavaScript 设置自定义属性,这里有个相当简单的 API:</p> <pre><code>const elm = document.documentElement; elm.style.setProperty('--USER-THEME-COLOR', 'tomato'); </code></pre> <p>在这里,我设置了 <code>--USER-THEME-COLOR</code> 元素的值,换言之,<code>:root</code> 将被所有元素继承。</p> <p>这并不是一个新的 API, 它仅仅只是用于更新元素样式的 JavaScript 方法。这些是内联样式,因此它们比普通 CSS 具有更高的权重。</p> <p>这让局部自定义变得很容易:</p> <pre><code>.note { --note-color: #eaeaea; } .note { background: var(--note-color); } </code></pre> <p>在这里,我设置了默认值 <code>--note-color</code> 并将其作用域限制在了 <code>.note</code> 伟德1946手机版下。即使在这个简单的例子中,我也将变量声明与属性声明分开。</p> <pre><code>const elm = document.querySelector('#note-uid'); elm.style.setProperty('--note-color', 'yellow'); </code></pre> <p>然后,我定位了一个 <code>.note</code> 元素的实例,并仅更改该实例自定义属性 <code>--note-color</code> 的值。这将比默认值具有更高的权重。</p> <p>你可以看<a href="http://xxysy.com/quot;//codepen.io/MadeByMike/pen/WzbGdE?editors=0110">使" React 的例子</a>来了解它是如何工作的。这些用户首选项可以保存在本地存储中,在更大应用中也可以保存到数据库里。</p> <h3>使用自定义属性控制颜色</h3> <p>除了十六进制值和已命名的颜色之外,CSS 还具有诸如 <code>rgb()</code> 和 <code>hsl()</code> 这样的颜色方法可以使用。这些允许我们为伟德1946手机版设置例如色调或亮度等特定的颜色属性。自定义属性可以与这些方法结合使用。</p> <pre><code>:root { --hue: 25; } body { background: hsl(var(--hue), 80%, 50%); } </code></pre> <p>这很有用,而预处理器中提供了更多更高级的颜色方法,我们可以通过这些方法去实现颜色的亮化、变暗或去饱和等功能:</p> <pre><code>darken($base-color, 10%); lighten($base-color, 10%); desaturate($base-color, 20%); </code></pre> <p>如果浏览器自身就提供了这些方法那就更好了。<a href="//www.w3.org/TR/css-color-4/#funcdef-color-mod">他们即将到来</a>,但在 CSS 原生支持拥有这些功能之前,自定义属性刚好能填补这个空缺。</p> <blockquote> <p>有关于颜色控制相关的内容,去年@Erik Jung写了一篇文章来<a href="//cloudfour.com/thinks/building-themes-with-css4-color-features/">介绍CSS Color的特性</a>,其中<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css4/color-mod.html">使用<code>color-mod()</code>函数修改颜色</a>是其中最有意思的一个。只是浏览器对该属性还不怎么支持。不过,@Ahmad Shadeed写了一篇文章,介绍了<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/the-power-of-rgba.html">使用<code>rgba()</code>模拟出<code>color-mod()</code>函数的特性</a>。</p> </blockquote> <p>我们已经看到,自定义属性不仅可以在比如 <code>rgb()</code>、<code>hsl()</code> 等颜色方法中使用,也可以在 <code>calc()</code> 中使用。这意味着我们可以通过乘法把一个数转换成百分比的形式,例如 <code>calc(50 * 1%) = 50%</code>。</p> <pre><code>:root { --lightness: 50; } body { background: hsl(25, 80%, calc(var(--lightness) * 1%)); } </code></pre> <p>我们将亮度值存储为整数的原因是:在将其转化为百分比之前可以使用 <code>calc</code> 方法来进行转换。举个例子,如果我想一个颜色变暗 <code>20%</code>,我可以将其亮度值乘以它 <code>0.8</code> 实现。通过自定义属性,将亮度的计算方法限制在局部作用域下,可以使我们的代码可读性更强:</p> <pre><code>:root { --lightness: 50; } body { --lightness: calc(var(--lightness * 0.8)); background: hsl(25, 80%, calc(var(--lightness) * 1%)); } </code></pre> <p>我们甚至可以抽象出更多的计算方法,并创建类似<a href="http://xxysy.com/quot;//codepen.io/MadeByMike/pen/YLQWeb">基" CSS 自定义属性的颜色拓展功能</a>中提到的方法一样。这个例子对于大多数主题的实际情况来说可能相对复杂,但是它充分展示了动态自定义属性的能力。</p> <h3>简化主题</h3> <p>使用自定义属性的优点之一是能够让主题的创建更加的简单。应用程序不需要知道自定义属性是如何使用的。相反,我们通过 JavaScript 或服务器端代码来设置自定义属性的值,而这些值又直接由样式表控制。</p> <p>这意味着我们进一步将逻辑与设计分离。如果你有一个专业的设计团队,设计师可以通过更新样式表来决定如何应用自定义属性,而无需更改一行 JavaScript 或后端代码。</p> <p>自定义属性,将主题的复杂度移动到了 CSS 中,这种复杂性可能会对 CSS 的维护性产生负面影响,所以请可能保持主题的简单。</p> <h2>是时候使用自定义属性了</h2> <p>即使你的项目依然需要支持 IE10 和 IE11,你也可以使用自定义属性。本文中的大多数示例都与如何编写和构建 CSS 有关。但是,从可维护性的角度来说,这些好处是非常重要的,本文大多数示例只是减少了原本需要使用更复杂的代码才能实现的事情。</p> <p>我使用一个名为<a href="//github.com/MadLittleMods/postcss-css-variables"><code>postcss-css-variables</code></a>的工具将自定义属性的大部分方法转换为相同功能的静态方法。而其他类似的工具忽略了媒体查询或复杂选择器中的自定义属性,将其当作预处理变量来处理。</p> <p>这些工具不能做到的是模拟出自定义属性的实时特性。而这意味着失去了之前我们在主题和通过 JavaScript 更改属性中提到的动态特性。这在很多情况下也是可以接受的。毕竟基于不同的情况,自定义UI也不失为一种渐进式增强的方式,而默认的主题对于旧的浏览器来说也是完全可以接受的。</p> <h2>加载正确的样式表</h2> <p>使用 PostCSS 的有很多。我通过使用 Gulp 的进程来来区分新旧浏览器的样式表。一个我创建的 Gulp 任务如下:</p> <pre><code>import gulp from "gulp"; import sass from "gulp-sass"; import postcss from "gulp-postcss"; import rename from "gulp-rename"; import cssvariables from "postcss-css-variables"; import autoprefixer from "autoprefixer"; import cssnano from "cssnano"; gulp.task("css-no-vars", () =&gt; gulp .src("./src/css/*.scss") .pipe(sass().on("error", sass.logError)) .pipe(postcss([cssvariables(), cssnano()])) .pipe(rename({ extname: ".no-vars.css" })) .pipe(gulp.dest("./dist/css")) ); gulp.task("css", () =&gt; gulp .src("./src/css/*.scss") .pipe(sass().on("error", sass.logError)) .pipe(postcss([cssnano()])) .pipe(rename({ extname: ".css" })) .pipe(gulp.dest("./dist/css")) ); </code></pre> <p>这个结果将输出两个 CSS 文件:一个具有自定义属性的(<code>styles.css</code>)文件,另一个用于旧浏览器(<code>styles.no-vars.css</code>)。我希望在 IE10 和 IE11 浏览器中使用 <code>styles.no-vars.css</code> 这个文件,其它浏览使用常规的 CSS 文件。</p> <p>通常,我主张使用功能查询,但 <a href="http://xxysy.com/quot;//caniuse.com/#search=%40supports">IE1" 不支持功能查询</a>,可是我们已经大量使用了自定义属性,在这种情况下,为其提供不同样式表就显得有意义了。</p> <p>通过提供不同的样式表以避免无样式内容的闪烁并不是一个简单的事情。如果不需要自定义属性中的动态特性,可以考虑仅使用适用于所有浏览器的 <code>styles.no-vars.css</code> 文件,而自定义属性仅作为开发工具。</p> <p>如果你想充分利用自定义属性的所有动态特性,我建议使用<a href="//www.smashingmagazine.com/2015/08/understanding-critical-css/">关键的 CSS 技术</a>。基于这些技术,主样式表是异步加载的,而关键的 CSS 是内联的。你的页面的 <code>header</code> 可能看起来像这样:</p> <pre><code>&lt;head&gt; &lt;style&gt; /* inlined critical CSS */ &lt;/style&gt; &lt;script&gt; loadCSS('non-critical.css'); &lt;/script&gt; &lt;/head&gt; </code></pre> <p>我们可以扩展这个方法,来实现基于浏览器是否支持支持自定义属性来决定加载 <code>styles.css</code> 文件还是 <code>styles.no-vars.css</code> 文件的效果。我们可以这样来实现:</p> <pre><code>if ( window.CSS &amp;&amp; CSS.supports('color', 'var(--test)') ) { loadCSS('styles.css'); } else { loadCSS('styles.no-vars.css'); } </code></pre> <h2>总结</h2> <p>如果你想要更有效地管理 CSS、在使用响应式的功能上遇到困难、想要实现类似客户端主题的效果或者只是想尝试一下自定义属性,这篇文章应该可以帮你解答这些问题了。这不仅解释了 CSS 中动态变量和静态变量之间的区别,还有如下的其它的几条规则:</p> <ul> <li>将逻辑从设计中分离;</li> <li>如果 CSS 属性需要发生变化,可以考虑使用自定义属性;</li> <li>仅修改自定义属性的值,而不是修改自定义属性本身;</li> <li>全局变量通常是静态的。</li> </ul> <p>如果理解了以上这些条例,你会发现使用自定义属性比你想象的要容易得多,甚至可能会改变你对 CSS 的处理方式。</p> <h2>扩展阅读</h2> <ul> <li><a href="//www.smashingmagazine.com/2017/04/start-using-css-custom-properties">是时候使用自定义属性了</a>,@Serg Hospodarets 介绍的自定义属性的语法和特性的</li> <li><a href="//csswizardry.com/2016/10/pragmatic-practical-progressive-theming-with-custom-properties">渐进式实用的CSS自定义属性</a>,@Harry Roberts 介绍的更多关于主题的有用信息</li> <li><a href="http://xxysy.com/quot;//codepen.io/collection/naJLrB">自定义属性集合</a>,@Mik" Riethmuller 在 CodePen 上提供的大量的不同的示例</li> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/601.html">CSS自定义属性更多伟德1946网页版</a></li>" </ul> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/css-custom-properties-strategy-guide.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/css-custom-properties-strategy-guide.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/translations"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">译文</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/68.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/601.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS自定义属性</a></div></div></div> Sat, 07 Jul 2018 15:22:41 +0000 Airen 2427 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/drawing-images-with-css-gradients.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>特别声明,本文根据<a href="//css-tricks.com/author/jon-kantner/">@JON KANTNER</a>的《<a href="//css-tricks.com/drawing-images-with-css-gradients/">Drawing Images with CSS Gradients</a>》一文所整理。</p> </blockquote> <p>这里所说的绘制是指<strong>CSS图像</strong>,即使用HTML元素和CSS属性绘制的图像。它们看起来像是Adobe Illustrator绘制的<code>svg</code>,但它们是在浏览器中渲染出来的。我所见过的一些技巧是使用<code>border</code>、<code>box-shadow</code>和<code>clip-path</code>来绘制图像。如果你在<a href="//codepen.io/search/pens?q=daily%20css%20images&amp;page=1&amp;order=popularity&amp;depth=everything&amp;show_forks=false">Codepen搜索“daily css images”</a>,你会发现有很多优秀的案例。我自己也画了一些,也做过<a href="http://xxysy.com/quot;//codepen.io/jkantner/pen/ELvMBE">一些极限挑战</a>,就是在一个元素上使用<code>background</code>和尽量使用其他属性来绘制图像。</p>" <p>让我们来睦看如何创建CSS图像。</p> <h2>方法</h2> <p>了解<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/147.html"><code>background</code></a>语法和<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/41.html">CSS渐变</a>的工作原理是使用一个元素绘制任何东西所需要基础。先来看<code>background</code>语法:</p>" <pre><code>background: &lt;'background-color'&gt; || &lt;image&gt; || &lt;position&gt; [ / &lt;size&gt; ]? || &lt;repeat&gt; || &lt;attachment&gt; || &lt;origin&gt; || &lt;clip&gt;; </code></pre> <p>除了<code>background-position</code>和<code>background-size</code>之间必须要有一个<code>/</code>来隔开之外,其他任何一个属性都可以以任何顺序出现。这里需要特别注意的是:<code>background-position</code>和<code>background-size</code>在简写的<code>background</code>属性中必须要有<code>/</code>,否则会得到意想不到的结果。另外不是所有属性都必须使用上的,比如,我们有可能不会使用<code>background-color</code>、<code>background-repeat</code>、<code>background-attachment</code>、<code>background-origin</code>或<code>background-clip</code>。如此下来就剩下了<code>background-image</code>、<code>background-size</code>和<code>background-position</code>。由于<code>background-repeat</code>的默认值是<code>repeat</code>,所以必须将其设置为<code>no-repeat</code>。如果背景中有内容需要重复,我们可以使用<code>repeating-linear-gradient()</code>和<code>repeating-radial-gradient()</code>两个渐变属性。在这种情况之下,我们的CSS可以这样写:</p> <pre><code>.image { background: &lt;image&gt; &lt;position&gt; / &lt;size&gt;; background-repeat: no-repeat; } </code></pre> <p>如果您从未接触过CSS渐变相关的知识,建议您花点时间先阅读下面几篇文章:</p> <ul> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/new-css3-linear-gradient.html">再说CSS3渐变:线性渐变</a></li> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/new-css3-radial-gradient.html">再说CSS3渐变:径向渐变</a></li> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/do-you-really-understand-css-linear-gradients.html">你真的理解CSS的linear-gradient?</a></li> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/why-do-we-have-repeating-linear-gradient-anyway.html">为什么要使用repeating-linear-gradient</a></li> </ul> <p>我们甚至可以使用多组背景参数(浏览器支持<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/content/css3-multiple-backgrounds">多背景</a>的运用)!因此,我们只需要使用逗号将每组背景参数分隔开来:</p> <pre><code>.image { background: &lt;image&gt; &lt;position&gt; / &lt;size&gt;, &lt;image&gt; &lt;position&gt; / &lt;size&gt;, &lt;image&gt; &lt;position&gt; / &lt;size&gt;; background-repeat: no-repeat; } </code></pre> <p>上面的结构是我们如何绘制图像的基础。请记住,<strong>多背景中渲染的顺序与绝对或固定位置元素的顺序刚好相反</strong>。第一个会出现在顶部而不是底部。换句话说,下面的代码中的径向渐变将由上到下渲染呈现(红色在最顶部,蓝色在最底下):</p> <pre><code>.circles { background: radial-gradient(7em 7em at 35% 35%, red 50%, transparent 50%), radial-gradient(7em 7em at 50% 50%, gold 50%, transparent 50%), radial-gradient(7em 7em at 65% 65%, blue 50%, transparent 50%); background-repeat: no-repeat; width: 240px; height: 240px; } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/3circles-1.png" alt="" /></p> <p>简单的理解,<code>background</code>中有多组背景时,渲染出来的背景顺序和书写的顺序一致。</p> <h2>绘制</h2> <p>我们将使用<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/302.html">Sass</a>(SCSS)来绘制这些图像,这样做主要是可以将变量用于调色板。这将代码变得更短,更易于阅读和更易于修改颜色(将颜色变得更暗或更浅)。我们可以使用<" href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/start-using-css-custom-properties.html">CSS自定义属性</a>,而不用Sass,但由于IE还不支持CSS自定义属性,所以还是继续使用Sass。为了解释这是如何工作的,我们将使用线性和径向渐变来绘制CSS图像。</p> <blockquote> <p>特别声明,文章主要出发点是向大家阐述如何使用CSS的渐变来绘制CSS图像,另外为了加强CSS自定义属性的理解和积累相关经验,接下来的示例,译者改变了原作者的初衷,将在示例中使用<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/601.html">CSS自定义属性</a>来替代原文中的Sass变量。</p>" </blockquote> <h2>设置一个调色板</h2> <p>我们的调色板将用<code>RGB</code>或<code>HSL</code>颜色组成。稍后我将解释为什么要用这两种格式来声明<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/playing-with-css3-colors">颜色</a>。在本例中,我将使用<code>RGB</code>颜色格式。</p> <blockquote> <p>有关于颜色更深入的介绍,可以阅读<a href="http://xxysy.com/quot;//twitter.com/jlfwong">@Jami" Wong</a>的《<a href="http://xxysy.com/quot;//jamie-wong.com/post/color/">Color" From Hexcodes to Eyeballs</a>》一文和《<a href="http://xxysy.com/quot;//www.zcfy.cc/article/improving-color-on-the-web-webkit-922.html">优化Web上的颜色</a>》一文。</p>" </blockquote> <pre><code>--r: rgb(255,0,0); // hsl(0,100%,50%) --o: rgb(255,128,0); // hsl(32,100%,50%) </code></pre> <p>我个人喜欢使用简短的代码,使用至少一字母来表示每种颜色(例如,<code>--r</code>表示<code>red</code>颜色),这样易于阅读。如果使用较深或较浅的一种颜色,我将在字母前增加字母<code>d</code>表示暗色,<code>l</code>表示亮色。这里用<code>dr</code>表示深红,<code>lr</code>表示浅红。如果需要两个以上的阴影,我就会在末尾添加一个数字来表示阴影级别。例如,深红色的<code>--dr1</code>,深红色的<code>--dr2</code>,浅红色的<code>--lr1</code>,浅红色的<code>--lr2</code>。这样一来,调色板应该是这样的(首先是深色、然后是正常色,接下来是浅色):</p> <pre><code>--dr1: rgb(224,0,0); --dr2: rgb(192,0,0); --r: rgb(255,0,0); --lr1: rgb(255,48,48); --lr2: rgb(255,92,92); </code></pre> <h2>设置缩放和画布</h2> <p>我们给图像尺寸使用<code>em</code>单位,这样图像就可以方便地按比例调整大小。由于<code>1em</code>等于元素的<code>font-size</code>,因此如果要改变图像大小,只需要相应调整<code>font-size</code>大小。我们将<code>font-size</code>设置为<code>10px</code>,<code>width</code>和<code>height</code>设置为<code>24em</code>。将<code>font-size</code>设置为<code>10px</code>是最简单的,因为基于它做数学计算是最简单的,因此<code>24em</code>你就知道它对应的是<code>240px</code>。然后画布的边框设置<code>1px</code>的灰色。</p> <blockquote> <p><code>em</code>是<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/333.html">CSS单位</a>中的其中一个,也是易于造成计算混乱的单位之一,如果你感兴趣,<" href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/px-to-em">可以点击这里进行了解</a>。当然,你也可以使用CSS处理器中的函数功能来做相应的转换,比如<a href="//css-tricks.com/snippets/sass/px-to-em-functions/">px2em</a>这样的。</p> </blockquote> <pre><code>--r: rgb(255,0,0); // hsl(0,100%,50%) --o: rgb(255,128,0); // hsl(32,100%,50%) .image { background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 24em; height: 24em; } </code></pre> <p>另外前面提到,为了易于计算,将<code>font-size</code>的值设置为<code>10px</code>,但要注意的是,Chrome浏览器的最小的<code>font-size</code>的值为<code>12px</code>,所以在实际使用的时候,要注意这个细节。</p> <p>此外,你还可以通过使用<code>calc()</code>和<code>viewport</code>单位来启用响应性。也许我们可以使用像<code>calc(10px + 2vmin)</code>这样的东西,不过为了简单易于理解,这里还是使用<code>10px</code>吧。</p> <p><code>calc()</code>和<code>viewport</code>结合在一起可以计算出混合字号,这样可以实现在一个范围内的视窗下有具体的像素值。其有一个典型的计算公式:</p> <p><img src="/sites/default/files/blogs/2016/1612/advanced-calc-800-opt.pn" alt="" /></p> <p>有关于这方面更详细的介绍,可以阅读下面的相关文章:</p> <ul> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/responsive/precise-control-responsive-typography.html">如何精确控制响应式排版</a></li>" <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/viewport-based-typography.html">基于视窗单位的排版</a></li> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css3/a-more-modern-scale-for-web-typography.html">Web排版的缩放</a></li> <li><a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/css-polyfluidsizing-using-calc-vw-breakpoints-and-linear-equations.html">实现精准的流体排版原理</a></li> </ul> <h2>绘制图形</h2> <p>有趣的部分从这里开始。在正中间绘制一个<code>8em x 8em</code>在小的红色正方形。这个红色正方使用使用<code>linear-gradient()</code>来绘制,不过起始颜色和终止颜色相同。</p> <pre><code>.image { background: linear-gradient(var(--r), var(--r)) 50% 50% / 8em 8em; ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/square.png" alt="" /></p> <p>如果想绘制一个梯形,只需要在渐变中设置一个<code>60deg</code>的角度值,用来指定渐变的方向。与此同时,在颜色面板上添加<code>--T</code>自定义属性的值设置为<code>transparent</code>。然后将<code>--r</code>和<code>--T</code>的位置都设置为<code>63%</code>(右上角被截):</p> <pre><code>--T: transparent; .image { background: linear-gradient(60deg, var(--r) 63%, var(--T) 63%) 50% 50% / 8em 8em; ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/trapezoid_raw.png" alt="" /></p> <p>在两个值上设置相同的停止位置,斜切的一侧会有毛边。如果你仔细观察它,它看起来像下面这样:</p> <p><img src="/sites/default/files/blogs/2018/1807/trapezoid_wnhgld.png" alt="" /></p> <p>为了让效果不会有毛边,将其中一个停止的值稍微调整一点(大约<code>1%</code>),这样就会使用毛边去除掉,边缘更平滑。在上面的示例中,将<code>--r</code>的<code>63%</code>换成<code>62%</code>。</p> <p>这将是一个圆边的问题,同时在径向渐变中也存在,稍后会看到。如果用的不是Safari浏览器查看效果,那么即使切换到非透明颜色(比如<code>orange</code>),一切看起来都很不错。但在Safari中,你会注意到斜切的一边有一些黑虚边。</p> <p><img src="/sites/default/files/blgos/2018/1807/trapezoid_smooth_safari.png" alt="" /></p> <p>这是因为Safari中的<code>transparent</code>关键词始终是黑色透明的,因此我们会看到一些黑色的虚边。我真的希望苹果能解决这个问题,但他们永远不会。现在,让我们在<code>--r</code>添加一个新的属性<code>--redT</code>,并将其值设置为红色透明度(<code>rgba(255, 0, 0, 0)</code>)。再把<code>--T</code>删除,因为将不会再用到这个自定义属性。</p> <pre><code>--rT: rgba(255,0,0,0); // hsla(0,100%,50%,0) </code></pre> <p>然后,我们使用<code>--redT</code>替换<code>transparent</code>。这就解决了Safari浏览器中虚边的问题。</p> <pre><code>.image { background: linear-gradient(60deg,var(--r) 62%, var(--rT) 63%) 50% 50% / 8em 8em; ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/trapezoid_smooth.png" alt="" /></p> <p>你可能会感到好奇,为什么我们不使用十六进制颜色?那是因为<a href="http://xxysy.com/quot;//caniuse.com/#search=rrggbbaa">IE和Edge不支持<code>#rgba</code>和<code>#rrggbbaa</code>的语法</a>(事实上,HE" 早在2016年末就有了<code>alpha</code>通道,你不知道吧)。我也希望它能尽可能地得到所有浏览器支持。我们还是将颜色格式保持一致吧。</p> <p>现在把图形垂直移动到<code>20%</code>,并且在其下面绘制一个相同尺寸的<code>orange</code>圆。此外,为其透明版本添加另一个自定义属性<code>--oT</code>。同样的,为了边缘光滑,起始值和终址值之间也有一个<code>1%</code>的差值。</p> <pre><code>--oT: rgba(255,128,0,0); // hsla(32,100%,50%,0) .image { background: linear-gradient(60deg,var(--r) 62%, var(--rT) 63%) 50% 20% / 8em 8em, radial-gradient(8em 8em at 50% 80%, var(--o) 49%, var(--oT) 50%); ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/trapezoid_circle.png" alt="" /></p> <p>为了与我们的尺寸保持一致,第二个颜色停止值应该是<code>50%</code>,而不是<code>100%</code>。</p> <h2>图形位置</h2> <p>渐变的位置取决于单位采用的是固定的还是百分比。假设我们把这两个渐度都变成正方形,并试着把它们横向放到<code>div</code>中。</p> <pre><code>.image { background: linear-gradient(var(--r), var(--r)) 24em 20% / 8em 8em, linear-gradient(var(--o), var(--o)) 100% 80% / 8em 8em; ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/squares.png" alt="" /></p> <p>红色方块完全移出画布,橙色方块的右边与画布右边相连接。使用固定单位就像在HTML5的<code>canvas</code>中放置绝对定位的元素或绘制图形。从这个意义上说,原点在左上方。当使用百分比设置背景大小时,<code>div</code>获得“假填充”是<code>background-size</code>的一半。同时,背景的原点是居中的(不要与<code>background-origin</code>混淆,背景原点是指盒模型的左上角)。</p> <p><img src="/sites/default/files/blogs/2018/1807/squares2.png" alt="" /></p> <p>现在,我们把渐变换成径向渐变来绘制圆,<code>x</code>位置设置为<code>24em</code>和<code>100%</code>,最后的效果是两个圆的另一半都被移到画布的外面(被切掉一半)。这是因为,我们这样写背景,原点总是在中间:</p> <pre><code>.image { background: radial-gradient(8em 8em at 24em 20%, var(--r) 49%, var(--rT) 50%), radial-gradient(8em 8em at 100% 80%, var(--o) 49%, var(--oT) 50%); ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/circles.png" alt="" /></p> <p>如果我们重写背景,让位置和大小都在渐变之后,并且使用<code>100% 100% at center</code>,这样一来,它们会被认为是线性渐变。红色的移到画布外面,橙色的在画布最右边。“假填充”再次出现在橙色部分。</p> <pre><code>.image { background: radial-gradient(100% 100% at center, var(--r) 49%, var(--rT) 50%) 24em 20% / 8em 8em, radial-gradient(100% 100% at center, var(--o) 49%, var(--oT) 50%) 100% 80% / 8em 8em; ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/circles2.png" alt="" /></p> <p>没有一种正确的方法来定位形状,但是要将其定位成一个绝对的或固定的HTML元素,最好是使用固定的单位。如果需要一个快速的方法来放置一个形状(使用<code>position/size</code>)在死中心,<code>50%</code>是最好的选择,因为形状的原点将是它的中心。如果它应该触及可侧,那就用<code>100%</code>。</p> <h2>图形尺寸</h2> <p>CSS背景下的大小调整和我们预期的一样,但是它们仍然受到固定或百分比的单位类型的影响。同样拿方块来举例,把它们的宽度改变<code>10em</code>,红色的方块向右展开,橙色的方块向两边展开。</p> <pre><code>.image { background: linear-gradient(var(--r), var(--r)) 12em 20% / 10em 8em, linear-gradient(var(--o), var(--o)) 50% 80% / 10em 8em; ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/resized_squares.png" alt="" /></p> <p>如果在<code>y</code>位置使用<code>em</code>单位,形状会向上或向上收缩改变高度。如果我们用百分比单位,会在两个方向展开。</p> <p>刚才,我们讨论了用径向渐变画圆的两种方法。第一种方法是在<code>(</code>和<code>at</code>指定<code>width</code>和<code>height</code>,然后在<code>at</code>后指定位置:</p> <pre><code>.image { background: radial-gradient(8em 8em at 50% 50%, var(--r) 49%, var(--rT) 50%); ... } </code></pre> <p>第二种方法是在<code>(</code>和<code>at</code>之间使用<code>100% 100%</code>,然后给出位置和尺寸:</p> <pre><code>.image { background: radial-gradient(100% 100% at 50% 50%, var(--r) 49%, var(--rT) 50%) 50% 50% / 8em 8em; ... } </code></pre> <p>这些方法都可以使用径向渐变画圆,但会产生不同的输出,那是因为:</p> <ul> <li>第一种方法占用整个<code>div</code>,因为没有真正的<code>background-position</code>和<code>background-size</code></li> <li>第二种方法设置了一个边框,有实际的位置和大小。因此,它就像一个线性渐变</li> </ul> <p>假设我们用<code>--o</code>替换<code>--rT</code>。你会看到橙色覆盖白色。如果使用第二种方法,你将很容易地注意到橙色所显示的边框。</p> <p><img src="/sites/default/files/blogs/2018/1807/radial-grad-red2orange.png" alt="" /></p> <p>另外,使用<code>circle</code>或<code>ellipse</code>替换<code>100% 100%</code>的目的是让圆占据整个包围盒。它甚至能让我们完全控制它的尺寸。那样的话,如果你把<code>50% 50%</code>换成别的东西,它就会保持不变。如果使用这两个关键字中的一个,在居中时圆的边缘只有大约<code>71%</code>的距离,在调整位置时变得更加扭曲。例如,当我们将<code>circle</code>和<code>ellipse</code>的<code>x</code>坐标改为<code>0</code>时,会发生以下情况:</p> <p><img src="/sites/default/files/blogs/2018/1807/radial-circle-v-ellipse.png" alt="" /></p> <p>从长远来看,你可以将语法重新想象为<code>radial-gradient(width height at x y)</code>或<code>radial-gradient(100% 100% at 限定框x位置 限定框y位置) x y / width height</code>。如果你只是绘制一个圆或椭圆,你可以使用第一种简化的代码。如果画一个圆的一部分或者一个环的一部分,那么第二种简化的方法是很好的选择。在接下来的示例中,我们将会有很多这样的应用。</p> <h2>案例</h2> <p>准备好了吗?我们将一步一步地介绍三个例子。前两个是静态的,一个有很多半圆,另一个有圆形也有矩形。最后一个例子将更小,但重点是动画。</p> <h3>绘制雨伞</h3> <p>这个雨伞将是我们要绘制的第一个静态图像:</p> <p><img src="/sites/default/files/blogs/2018/1807/parasol.png" alt="" /></p> <p>我们的调色板配置有<code>red</code>(<code>--r</code>和<code>--rT</code>),<code>white</code>(<code>--w</code>和<code>--wT</code>),<code>orange</code>(<code>--o</code>和<code>--oT</code>)和深橙色(<code>--do</code>和<code>--doT</code>):</p> <pre><code>--r: rgb(255,40,40); --rT: rgba(255,40,40,0); --w: rgb(240,240,240); --wT: rgba(240,240,240,0); --o: rgb(255,180,70); --oT: rgba(255,180,70,0); --do: rgb(232,144,0); --doT: rgba(232,144,0,0); </code></pre> <p>绘图区域的大小为<code>30em x 29em</code>。</p> <pre><code>.parasol { // 背景相关的样式放在这里 background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 30em; height: 29em; } </code></pre> <p>在<code>background-repeat</code>之前将会放置绘制雨伞所有的样式。首先,添加绘制伞把的样式代码:</p> <pre><code>.parasol { background: // 1 radial-gradient(200% 200% at 100% 100%, var(--do) 49%, var(--doT) 50%) 14em 0 / 1em 1em, radial-gradient(200% 200% at 0% 100%, var(--o) 49%, var(--oT) 50%) 15em 0 / 1em 1em, // 2 linear-gradient(90deg, var(--do) 50%, var(--o) 50%) 14em 1em / 2em 25em, // 3 radial-gradient(100% 200% at 50% 0, var(--oT) 0.95em, var(--o) 1em, var(--o) 1.95em, var(--do) 2em, var(--do) 2.95em, var(--doT) 3em) 14em 26em / 6em 3em, // 4 radial-gradient(200% 200% at 100% 100%, var(--o) 49%, var(--oT) 50%) 18em 25em / 1em 1em, radial-gradient(200% 200% at 0% 100%, var(--do) 49%, var(--doT) 50%) 19em 25em / 1em 1em; ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/parasol_step1.png" alt="" /></p> <p>上面一坨代码,估计一下子无法理解(对于初学CSS的同学而言)。把上面的代码拆分一下:</p> <pre><code>// 1 radial-gradient(200% 200% at 100% 100%, var(--do) 49%, var(--doT) 50%) 14em 0 / 1em 1em, radial-gradient(200% 200% at 0% 100%, var(--o) 49%, var(--oT) 50%) 15em 0 / 1em 1em, </code></pre> <p>绘制伞把顶部,即一个<code>1em x 1em</code>的半圆。为了让它们占据整个容器,把整个圆圈放大了两倍(设置 <code>200% 200%</code>),它们分别位于右下角和左下角。我们也可以使用关键字来设置圆的位置,比如<code>bottom right</code>和<code>bottom left</code>,但使用百分比,要简短些。注意,两个颜色停止之间有一个<code>1%</code>的位置差距,以确保绘制的图形效果平滑。</p> <p><img src="/sites/default/files/blogs/2018/1807/parasol-step-1-1.png" alt="" /></p> <pre><code>// 2 linear-gradient(90deg, var(--do) 50%, var(--o) 50%) 14em 1em / 2em 25em, </code></pre> <p>接着绘制最长的那部分,这部分是一个从深橙色到橙色的长矩形。这两个颜色的停止位置不需要有一个很小的差值,因为这部分没有曲线,也没有斜切角。</p> <p><img src="/sites/default/files/blogs/2018/1807/parasol-step-1-2.png" alt="" /></p> <pre><code>// 3 radial-gradient(100% 200% at 50% 0, var(--oT) 0.95em, var(--o) 1em, var(--o) 1.95em, var(--do) 2em, var(--do) 2.95em, var(--doT) 3em) 14em 26em / 6em 3em, </code></pre> <p>第三部分相对而言要复杂一些,因为我们要保持一个<code>2em</code>直径的弧形。画这个圆弧,将<code>background-size</code>设置为<code>6em x 3em</code>,两者之间有一个<code>2em</code>的间距。然后在中心处使用径向渐变,每一个停止的位置都发生在<code>1em</code>处,为了让圆弧平滑,设置了一个差值为<code>.05em</code>。</p> <p><img src="/sites/default/files/blogs/2018/1807/parasol-step-1-3.png" alt="" /></p> <pre><code>// 4 radial-gradient(200% 200% at 100% 100%, var(--o) 49%, var(--oT) 50%) 18em 25em / 1em 1em, radial-gradient(200% 200% at 0% 100%, var(--do) 49%, var(--doT) 50%) 19em 25em / 1em 1em; </code></pre> <p>最后一部分和第一部分一样,只是它们的位置调整了。另外颜色也互换了一下。</p> <p><img src="/sites/default/files/blogs/2018/1807/parasol-step-1-4.png" alt="" /></p> <p>把这四个部分结合起来,就绘制出雨伞的雨把。</p> <p><img src="/sites/default/files/blogs/2018/1807/parasol-step-1-5.gif" alt="" /></p> <p>雨伞的伞把绘制出来了,接下来把下面的代码添加到最顶部,绘制伞布:</p> <pre><code>// 雨伞伞布 radial-gradient(100% 200% at 50% 100%, var(--r) 50%, var(--rT) 50.25%) 50% 1.5em / 9em 12em, radial-gradient(100% 200% at 50% 100%, var(--w) 50%, var(--wT) 50.25%) 50% 1.5em / 21em 12em, radial-gradient(100% 200% at 50% 100%, var(--r) 50%, var(--rT) 50.25%) 50% 1.5em / 30em 12em, </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/parasol_step2.png" alt="" /></p> <p>为了画出这部分的半圆,我们使用了<code>100% 200%</code>的径向渐变,使每个直径与背景宽度相匹配,但高度是背景的两倍,并且在底部居中。通过从下到上的排序,使得最大的在下面,最小的在上面。这样就得到了我们想要的曲线。</p> <p><img src="/sites/default/files/blogs/2018/1807/parasol_step2-1.gif" alt="" /></p> <p>随着渐变叠加越来越多,代码也就逐渐变得多起来,过一段时间就很难区分出哪个背景或一组背景对应图像的哪个部分。因此,为了更容易地确定它们,我们把它们分成几个小组,每个小组都添加上注释。这样易于后期能更读懂代码。</p> <pre><code>.parasol { background: // 雨伞伞布 radial-gradient(100% 200% at 50% 100%, var(--r) 50%, var(--rT) 50.25%) 50% 1.5em / 9em 12em, radial-gradient(100% 200% at 50% 100%, var(--w) 50%, var(--wT) 50.25%) 50% 1.5em / 21em 12em, radial-gradient(100% 200% at 50% 100%, var(--r) 50%, var(--rT) 50.25%) 50% 1.5em / 30em 12em, // 雨伞伞把 // 1 radial-gradient(200% 200% at 100% 100%, var(--do) 49%, var(--doT) 50%) 14em 0 / 1em 1em, radial-gradient(200% 200% at 0% 100%, var(--o) 49%, var(--oT) 50%) 15em 0 / 1em 1em, // 2 linear-gradient(90deg, var(--do) 50%, var(--o) 50%) 14em 1em / 2em 25em, // 3 radial-gradient(100% 200% at 50% 0, var(--oT) 0.95em, var(--o) 1em, var(--o) 1.95em, var(--do) 2em, var(--do) 2.95em, var(--doT) 3em) 14em 26em / 6em 3em, // 4 radial-gradient(200% 200% at 100% 100%, var(--o) 49%, var(--oT) 50%) 18em 25em / 1em 1em, radial-gradient(200% 200% at 0% 100%, var(--do) 49%, var(--doT) 50%) 19em 25em / 1em 1em; background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 30em; height: 29em; } </code></pre> <p>然后在雨伞的伞布和伞把之间添加另一部分背景,用来绘制伞布边缘的弧形效果。为了确定每个线段的宽度,我们必须得到红白相交点之间的距离。它们加起来必须是<code>30em</code>。</p> <p><img src="/sites/default/files/blogs/2018/1807/parasol_prestep3.png" alt="" /></p> <p>从白色和最窄的红色半圆开始,从白色的宽度<code>21em</code>中减去红色的<code>9em</code>宽度,再除以<code>2</code>,得到两个白色部分的宽度(也就是上图中<code>b</code>的宽度),结果是<code>6em</code>(<code>b = (21 - 9) / 2 = 6em</code>)。中间的红色线段是<code>9em</code>(<code>21 - (6 + 6) = 9em</code>)。现在剩下的是最外面的红色线段(图中的<code>a</code>点),从最大的红色半圆的宽度<code>30em</code>减去现在得到的和(也就是中间白色的宽度<code>21em</code>),再除以<code>2</code>。这样<code>a</code>点的值为<code>(30 - 21) / 2 = 4.5em</code>。</p> <pre><code>.parasol { background: ... // 雨伞伞布边缘的弧形 radial-gradient() 0 13.5em / 4.5em 3em, radial-gradient() 4.5em 13.5em / 6em 3em, radial-gradient() 50% 13.5em / 9em 3em, radial-gradient() 19.5em 13.5em / 6em 3em, radial-gradient() 25.5em 13.5em / 4.5em 3em, ... } </code></pre> <p>为了画出与我们画的上半部分相似的圆,我们从每个形状颜色的透明颜色开始,使它们类似圆弧桥。我们还将在每个渐变宽度上增加<code>5%</code>(而不是背景框宽度),以便相邻背景形状的每个点不会过于尖锐和薄。</p> <pre><code>.parasol { background: // 雨伞伞布 ... // 雨伞伞布边缘的弧形 radial-gradient(105% 200% at 50% 100%, var(--rT) 49%, var(--r) 50%) 0 13.5em / 4.5em 3em, radial-gradient(105% 200% at 50% 100%, var(--wT) 49%, var(--w) 50%) 4.5em 13.5em / 6em 3em, radial-gradient(105% 200% at 50% 100%, var(--rT) 49%, var(--r) 50%) 50% 13.5em / 9em 3em, radial-gradient(105% 200% at 50% 100%, var(--wT) 49%, var(--w) 50%) 19.5em 13.5em / 6em 3em, radial-gradient(105% 200% at 50% 100%, var(--rT) 49%, var(--r) 50%) 25.5em 13.5em / 4.5em 3em, // 雨伞伞把 ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/parasol_step3.png" alt="" /></p> <p>最后,将不再需要那个灰色的辅助边框线,这时可以把<code>outline: 1px solid #aaa</code>样式删除。最终的雨伞效果 就完成了。如下所示:</p> <div style="margin-bottom: 20px;"><iframe id="pKmYwQ" src="//codepen.io/airen/embed/pKmYwQ?height=400&amp;theme-id=0&amp;slug-hash=pKmYwQ&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>绘制带圆角的矩形</h3> <p>接下来这个示例是使用同样的手法来绘制一个旧的iPhone模型,在这个模型中有比新模型更多的细节。这个模型有两个特点:两个带圆形的矩形和Home键。</p> <blockquote> <p>接下来的示例和<a href="//marvelapp.github.io/devices.css/"><code>Devices.css</code>中绘制的iPhone模型</a>有所不同,接下来的示例是使用CSS渐变在一个HTML元素上完成的。</p> </blockquote> <p><img src="/sites/default/files/blogs/2018/1807/iphone.png" alt="" /></p> <p>和前面的示例一样,同样先创建一个调色板。这个调色板包括用于Home键按钮边缘的黑色(<code>--bk</code>和<code>--bkT</code>),用于相机和话筒的灰色(<code>--g</code>和<code>--gT</code>),模型外边框的浅灰色(<code>--lg</code>和<code>--lgT</code>),镜头的蓝色(<code>--bl</code>和<code>blT</code>)和屏幕的深紫色(<code>--p</code>和<code>--pT</code>)。</p> <pre><code>:root { --bk: rgb(10,10,10); --bkT: rgba(10,10,10,0); --dg: rgb(50,50,50); --dgT: rgba(50,50,50,0); --g: rgb(70,70,70); --gT: rgba(70,70,70,0); --lg: rgb(120,120,120); --lgT: rgba(120,120,120,0); --bl: rgb(20,20,120); --blT: rgba(20,20,120,0); --p: rgb(25,20,25); --pT: rgba(25,20,25,0); } </code></pre> <p>设置一个<code>20em x 40em</code>画布和使用<code>10px</code>的<code>font-size</code>:</p> <pre><code>.iphone { // 背景样式放置在这 background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 20em; height: 40em; } </code></pre> <p>在开始绘制第一个圆角矩形之前,我们需要考虑圆角的半径,这里设置为<code>2em</code>。另外,我们还需要考虑给锁开关和音量按钮留一些空间,这里设置为<code>0.25em</code>。出于这个原因,矩形的大小将是<code>19.75em x 40em</code>。考虑到<code>2em</code>的圆角,我们需要两个线性渐变相交。那么矩形的宽度是<code>15.75em</code>(<code>19.75 - 2 x 2 = 15.75em</code>)和高度是<code>36em</code>(<code>40 - 2 x 2 = 36em</code>)。第一个位置是<code>2.25em 0</code>,第二个位置是<code>0.25em 2em</code>:</p> <pre><code>.iphone { background: // body linear-gradient() 2.25em 0 / 15.75em 40em, linear-gradient() 0.25em 2em / 19.75em 36em; ... } </code></pre> <p>模型浅灰色的边框厚度是<code>.5em</code>,第一个线性渐变从浅灰(<code>--lg</code>)到深灰(<code>--dg</code>),它们的结束位置都在<code>0.5em</code>位置,接着从深灰(<code>--dg</code>)到浅灰(<code>--lg</code>),而它们的结束位置都在<code>39.5em</code>(<code>40 - 0.5 = 39.5em</code>)。第二个线性渐变设置了一个<code>90deg</code>的角度,让渐变是一个水平渐变,这个渐变同样的从浅灰(<code>--lg</code>)到深灰(<code>--dg</code>),两者结束位置是<code>0.5em</code>,接着从深灰(<code>--dg</code>)到浅灰(<code>--lg</code>),它们的结束位置是<code>19.25em</code>(<code>19.75 - 0.5 = 19.25em</code>)。</p> <pre><code>.iphone { background: // body linear-gradient(var(--lg) 0.5em, var(--dg) 0.5em, var(--dg) 39.5em, var(--lg) 39.5em) 2.25em 0 / 15.75em 40em, linear-gradient(90deg, var(--lg) 0.5em, var(--dg) 0.5em, var(--dg) 19.25em, var(--lg) 19.25em) 0.25em 2em / 19.75em 36em; } </code></pre> <p><img src="/sites/default/fiels/blogs/2018/1807/iphone_step1.png" alt="" /></p> <p>分解一下,易于理解:</p> <pre><code>linear-gradient(var(--lg) 0.5em, var(--dg) 0.5em, var(--dg) 39.5em, var(--lg) 39.5em) 2.25em 0 / 15.75em 40em </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/iphone_step1-2.png" alt="" /></p> <pre><code>linear-gradient(90deg, var(--lg) 0.5em, var(--dg) 0.5em, var(--dg) 19.25em, var(--lg) 19.25em) 0.25em 2em / 19.75em 36em </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/iphone_step1-3.png" alt="" /></p> <p>动态组合一下:</p> <p><img src="/sites/default/files/blogs/2018/1807/parasol_step2-1-1.gif" alt="" /></p> <p>每个方形的角落将放置圆形的边缘。要创建这些形状,我们就需要使用径向渐变,它的大小是它们的边框的两倍,并且位于每个角落。把这四个圆形的代码放在模型主体之上:</p> <pre><code>.iphone { background: // 四个圆角 radial-gradient(200% 200% at 100% 100%, var(--dg) 1.45em, var(--lg) 1.5em, var(--lg) 50%, var(--lgT) 51%) 0.25em 0 / 2em 2em, radial-gradient(200% 200% at 0% 100%, var(--dg) 1.45em, var(--lg) 1.5em, var(--lg) 50%, var(--lgT) 51%) 18em 0 / 2em 2em, radial-gradient(200% 200% at 100% 0%, var(--dg) 1.45em, var(--lg) 1.5em, var(--lg) 50%, var(--lgT) 51%) 0.25em 38em / 2em 2em, radial-gradient(200% 200% at 0% 0%, var(--dg) 1.45em, var(--lg) 1.5em, var(--lg) 50%, var(--lgT) 51%) 18em 38em / 2em 2em, ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/iphone_step2a.png" alt="" /></p> <p>要得到<code>0.5em</code>厚的浅灰色末端,考虑一下渐变从哪里开始,然后算一下。因为浅灰色在最后,我们从<code>2em</code>中减去<code>.5em</code>。对于平滑度,从<code>1.5em</code>中去掉一点小距离<code>0.05em</code>,然后在后面的停止位置添加<code>1%</code>,变成<code>51%</code>。</p> <p>现在,如果我们将<code>font-size</code>修改为<code>40px</code>或更大来放大图像,我们会注意到圆角和平角之间的接缝(用橙色圈起来的位置):</p> <p><img src="/sites/default/files/blogs/2018/1807/iphone_step2b.png" alt="" /></p> <p>因为它们看起来很小,我们可以很容易地把它们补上,只要把字体大小改回<code>10px</code>就可以了。</p> <pre><code>.iphone { background: // body linear-gradient(var(--lg) 0.5em, var(--dg) 0.55em, var(--dg) 39.5em, var(--lg) 39.55em) 2.25em 0 / 15.75em 40em, linear-gradient(90deg, var(--lg) 0.5em, var(--dg) 0.55em, var(--dg) 19.175em, var(--lg) 19.25em) 0.25em 2em / 19.75em 36em; ... } </code></pre> <p>然后在一个线性渐变中,将添加锁开关和音量按钮来填充左边的<code>0.25em</code>空间。如果按钮和主体之间有一个<code>1px</code>的空间,我们可以在背景宽度(<code>0.3em</code>)上增加<code>0.05em</code>,这样它就不会突出到深灰色上。</p> <pre><code>.iphone { background: // 锁开关和音量按钮 linear-gradient(var(--lgT) 5em, var(--lg) 5em, var(--lg) 7.5em, var(--lgT) 7.5em, var(--lgT) 9.5em, var(--lg) 9.5em, var(--lg) 11em, var(--lgT) 11em, var(--lgT) 13em, var(--lg) 13em, var(--lg) 14.5em, var(--lgT) 14.5em) 0 0 / 0.3em 100%, ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/iphone_step3.png" alt="" /></p> <p>看起来我们可以使用三个浅灰到浅灰的渐变。只是在透明和不透明之间发生了些变化。</p> <p>接下来,添加Home键以及它里面正方形的平边。Home键大小是<code>1.5em x 1.5em</code>,其绘制和模型主体有相同的过程:两个相交线性渐变和圆角来组成。只不过要将它们放置水平方向正中间,这个时候<code>calc()</code>就非常有用了。<code>50% + 0.125em</code>为表达式,如果我们只将模型主体居中,那么每边将有<code>0.125em</code>空间。因此,我们向右移<code>0.125em</code>。相同的<code>x</code>定位将适用于两个背景上。</p> <pre><code>.iphone { background: // Home键 linear-gradient() calc(50% + 0.125em) 36.5em / 0.5em 1.5em, linear-gradient() calc(50% + 0.125em) 37em / 1.5em 0.5em, radial-gradient(3em 3em at calc(50% + 0.125em) 37.25em, var(--bkT) 1.25em, var(--bk) 1.3em, var(--bk) 49%, var(--bkT) 50%), ... } </code></pre> <p>类似于我们模型主体的线性渐变,停止将以浅灰色开始和结束,但中间是透明的。注意,我们在每个灰度到透明的转换之间留下了<code>0.05em</code>的间距,就像模型主体的圆形一样,为了确保圆角和内部的平角能融合起来。</p> <pre><code>.iphone { background: // Home键 linear-gradient(var(--lg) 0.15em, var(--lgT) 0.2em, var(--lgT) 1.35em, var(--lg) 1.35em) calc(50% + 0.125em) 36.5em / 0.5em 1.5em, linear-gradient(90deg, var(--lg) 0.15em, var(--lgT) 0.2em, var(--lgT) 1.3em, var(--lg) 1.35em) calc(50% + 0.125em) 37em / 1.5em 0.5em, radial-gradient(3em 3em at calc(50% + 0.125em) 37.25em, var(--bkT) 1.25em, var(--bk) 1.3em, var(--bk) 49%, var(--bkT) 50%), ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/iphone_step4.png" alt="" /></p> <p>顺便说一下,和前面一样,我们可以通过将<code>font-size</code>增加到至少<code>20px</code>来看看我们在做什么。这有点像图像编辑软件中的缩放工具。</p> <p>现在要把灰色方块的角精确到它们应该在的位置,首先要关注的是<code>x</code>的位置。同样从<code>calc(50% + 0.125em)</code>开始,然后加上或减去每一块的宽度,或者应该说是正方形的圆角半径。这些背景将超过最后三个。</p> <pre><code>.iphone { background: // Home键 radial-gradient(200% 200% at 100% 100%, var(--lgT) 0.3em, var(--lg) 0.35em, var(--lg) 0.48em, var(--lgT) 0.5em) calc(50% + 0.125em - 0.5em) 36.5em / 0.5em 0.5em, radial-gradient(200% 200% at 0% 100%, var(--lgT) 0.3em, var(--lg) 0.35em, var(--lg) 0.48em, var(--lgT) 0.5em) calc(50% + 0.125em + 0.5em) 36.5em / 0.5em 0.5em, radial-gradient(200% 200% at 100% 0%, var(--lgT) 0.3em, var(--lg) 0.35em, var(--lg) 0.48em, var(--lgT) 0.5em) calc(50% + 0.125em - 0.5em) 37.5em / 0.5em 0.5em, radial-gradient(200% 200% at 0% 0%, var(--lgT) 0.3em, var(--lg) 0.35em, var(--lg) 0.48em, var(--lgT) 0.5em) calc(50% + 0.125em + 0.5em) 37.5em / 0.5em 0.5em, ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/iphone_step5.png" alt="" /></p> <p>然后制作屏幕,屏幕是一个<code>17.25em x 30em</code>的矩形。就像Home键的一部分一样,使用<code>calc(50% + 0.125em)</code>让矩形水平居中。而且这个矩形从顶部<code>5em</code>位置处开始。</p> <pre><code>.iphone { background: // 屏幕 linear-gradient(var(--p), var(--p)) calc(50% + 0.125em) 5em / 17.25em 30em, ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/iphone_step6.png" alt="" /></p> <p>最后,将添加摄像头和扬声器。摄像头是一个简单的<code>1em x 1em</code>从蓝色到灰色的径向渐变。不过,纯灰色的扬声器会更复杂一些。这将是一个<code>5em x 1em</code>矩形和有带两个<code>0.5em</code>半径的圆弧。要画出来,先画一个矩形,宽度是<code>4em</code>,水平居中使用<code>calc(50% + 0.125em)</code>。然后使用<code>0.5em x 1em</code>的径向渐变画圆弧,这两个圆弧的位置分别是<code>100% 50%</code>和<code>50% 0%</code>。把圆弧放置到矩形左右两边,其最佳方式还是要使用<code>calc()</code>表达式。左边的将从主体中心减去矩形一半宽度和半圆宽度(<code>50% + 0.125em - 2em - 0.25em</code>)。右边的遵循同样的模式,但不是做减法,是做加法(<code>50% + 0.125em + 2em + 0.25em</code>)。</p> <pre><code>.iphone { background: // 摄像头 radial-gradient(1em 1em at 6.25em 2.5em, var(--bl) 0.2em, var(--g) 0.21em, var(--g) 49%, var(--gT) 50%), // 扬声器 radial-gradient(200% 100% at 100% 50%, var(--g) 49%, var(--gT) 50%) calc(50% + 0.125em - 2em - 0.25em) 2em / 0.5em 1em, radial-gradient(200% 100% at 0% 50%, var(--g) 49%, var(--gT) 50%) calc(50% + 0.125em + 2em + 0.25em) 2em / 0.5em 1em, linear-gradient(var(--g), var(--g)) calc(50% + 0.125em) 2em / 4em 1em, ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/iphone_step7.png" alt="" /></p> <p>最终的效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="RJzBWr" src="//codepen.io/airen/embed/RJzBWr?height=400&amp;theme-id=0&amp;slug-hash=RJzBWr&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h3>雷达图</h3> <p>你可能认为可以使用<code>background-position</code>让这些背景图像动起来(有动画效果),但是你只能做这么多。例如,一个独立的背景是不可能产生动画效果的。事实上,<code>background-position</code>动画通常不如<code>transform</code>的动画效果好,所以我不推荐它。</p> <p>如果想使图像的任何部分以我们希望的方式动画,我们可以借助伪元素<code>:before</code>或<code>:after</code>来完成。如果我们需要更多的选择,那么我们可以使用多个<code>div</code>。接下来我们要做一个雷达扫描的动画效果,如下图所示:</p> <p><img src="/sites/default/files/blogs/2018/1807/radar-anim.gif" alt="" /></p> <p>我们先画静态部分,灰色的框架和转盘。同样的,先创建一个调色板和写一些基本代码:</p> <pre><code>:root { --gn: rgb(0,192,0); --gnT: rgba(0,192,0,0); --dgn: rgb(0,48,0); --gy: rgb(128,128,128); --gyT: rgba(128,128,128,0); --bk: rgb(0,0,0); --bkT: rgba(0,0,0,0); } .radar { background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 20em; height: 20em; } </code></pre> <p>雷达图完全是个圆的,所以我们可以使用<code>border-radius: 50%</code>来搞定圆形。然后,可以使用一个<code>repeating-radial-gradient</code>来绘制这些圆环,它们之间的距离约为<code>1/3</code>。</p> <pre><code>.radar { background: /* rings */ repeating-radial-gradient(var(--dgn), var(--dgn) 2.96em, var(--gn) 3em, var(--gn) 3.26em, var(--dgn) 3.3em); background-repeat: no-repeat; border-radius: 50%; ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/radar_step1.png" alt="" /></p> <p>与前面的示例不同,这个示例没有使用<code>calc()</code>来设置水平居中,因为稍后使用伪元素时,IE将会渲染的很慢。接下来要在中间画四条相交的<code>0.4em</code>的直线,要知道在<code>10em</code>时,这条线的一半应该是<code>div</code>的一半。然后,两边同时减去<code>0.2</code>(<code>0.4 / 2 = 0.2em</code>)。换句话说,绿色的左边应该是<code>9.8em</code>,右边应该是<code>10.2em</code>。<code>45</code>度的对角线必须用<code>10em</code>乘以<code>2</code>的平方根,计算出它的中心(<code>10 × √2 ≈ 14.14</code>)。它是<code>10em</code>直角三角开最长边的长度。因此,每条对角线的边长大约为<code>13.94em</code>和<code>14.34em</code>。</p> <pre><code>.radar { background: // lines linear-gradient(var(--gnT) 9.8em, var(--gn) 9.8em, var(--gn) 10.2em, var(--gnT) 10.2em), linear-gradient(45deg,var(--gnT) 13.94em, var(--gn) 13.98em, var(--gn) 14.3em, var(--gnT) 14.34em), linear-gradient(90deg,var(--gnT) 9.8em, var(--gn) 9.8em, var(--gn) 10.2em, var(--gnT) 10.2em), linear-gradient(-45deg,var(--gnT) 13.94em, var(--gn) 13.98em, var(--gn) 14.3em, var(--gnT) 14.34em), ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/radar_step2.png" alt="" /></p> <p>为了防止对角线的像素化,我们在<code>green</code>和<code>transparent</code>之间留下<code>0.04em</code>的间隙。然后,为了模拟照明效果,添加一个透明到黑色的径向渐变。</p> <pre><code>.radar { background: // lighting radial-gradient(100% 100%, var(--bkT), var(--bk) 9.9em,var(--bkT) 10em), ... } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/radar_step3.png" alt="" /></p> <p>这就完成了雷达的静态部分。现在我们把灰色的框架和手柄放在<code>:before</code>,主要是用来添加动画。有一个原因,在这里没有包含坐标系统。因为手感器应该适合整个<code>div</code>,我们不希望它与框架重叠。</p> <p>这个伪元素要填满整个<code>div</code>的空间,这里使用绝对定位来做。</p> <pre><code>.radar { ... position: relative; &amp;:before { background-repeat: no-repeat; border-radius: 50%; content: ""; position: absolute; width: 100%; height: 100%; } } </code></pre> <p>然后,绘制手柄(会转动的那一部分),让它的大小只有容器的一半,并把它放在左上角。最后,在这之上,绘制灰色框架。</p> <pre><code>.radar { ... &amp;:before { animation: scan 5s linear infinite; background: // frame radial-gradient(var(--gyT) 9.20em, var(--gy) 9.25em, var(--gy) 10em, var(--gyT) 10.05em), // hand linear-gradient(45deg, var(--gnT) 6em, var(--gn)) 0 0 / 50% 50%; ... } } @keyframes scan { from { transform: rotate(0); } to { transform: rotate(1turn); } } </code></pre> <p>最终效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="YvoJab" src="//codepen.io/airen/embed/YvoJab?height=400&amp;theme-id=0&amp;slug-hash=YvoJab&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h2>总结</h2> <p>简单地说,这篇文章介绍了CSS绘制图像的方法。这里主要用到了:</p> <ul> <li>使用CSS自定义属性为颜色设置调色板</li> <li>禁用<code>background-repeat</code>为<code>repeat</code>,并且使用<code>em</code>为单位,更好的基于<code>font-size</code>做缩放</li> <li>要想得到想要的结果,需要进地大量的思考和实验</li> <li>从下到上绘制每个图形,这主要是考虑背景是按这个顺序呈现的,每个形状的背景语法遵循<code>background-positon / size</code>(是否包含位置和大小)</li> </ul> <p>从上面这几个示例中可以看出,基于一个HTML元素,使用CSS渐变可以绘制很多图像。不过要想得到想的结果,需要进行大量的思考和实验。从文章中我们学会了如何对生个背景进行排序,如何绘制圆的部分,圆角矩形,以及如何为圆弧和斜切角边缘平滑。要了解更多,请自由的剖析和研究<a href="http://xxysy.com/quot;//codepen.io/collection/Avgder/">我在Codepen上收集的其他例子</a>。</p>" <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/drawing-images-with-css-gradients.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/drawing-images-with-css-gradients.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/translations"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">译文</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/68.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/41.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">gradient</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/658.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">渐变</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/601.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS自定义属性</a></div></div></div> Fri, 06 Jul 2018 14:56:01 +0000 Airen 2426 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/viewport-device-scroll-document-size.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>在上一节中,学习了<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/get-element-position-and-size-using-javascript.html">JavaScript如何获取和设置元素位置和尺寸相关的方法</a>,另外在JavaScript的学习笔记当中也学习了<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/offset-scroll-client.html">视窗宽度、位置与滚动高度</a>相关的JavaScript方法与属性。今天继续来学习DOM中相关的知识,这篇文章将学习视窗、设备、滚动条和文档等相关的尺寸。其实在前两篇文章中都有涉及这些知识,为了让DOM系列相关的知识更完善,所以再花点时间整理一些这方面的技术点,加强印象。</p> <p>时至今日,构建Web应用程序是伟德19463331主要工作之一。这些Web应用程序要面对众多不同的设备终端,也就是说,我们需要让这些Web应用程序在各种屏幕、分辨率下都应该有一个较好的展示效果。</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-1.png" alt="" /></p> <p>要将一个Web应用程序适配众多终端屏幕,需要知道的是有多少可用的空间。如果你接触过<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/responsive">Web响应式设计</a>(We" Responsive Design),就知道,Web浏览器客户端就可以很好的处理。最简单的方式就是使用CSS的媒体查询来处理,但也有很多同学通过JavaScript对最终的结果进行一些控制。不过,使用JavaScript来做的话,有许多计算的事情要做。当然,这些计算虽然是JavaScript来处理,但最终还是由浏览器本身来完成。</p> <p>当涉及到使用JavaScript控制元素位置相关的交互内容时,不能仅依赖浏览器自动帮助我们做正确的事情。我们需要主动(人肉)地去做一些相关计算。听起来可怕,事实上并没有那么可怕,接下来的内容将告诉我们怎么通过JavaScript来做这些事情。当你阅读完这篇文章之后,你会惊叹的地说,原来就是这么的简单。</p> <h2>测量视窗的大小</h2> <p>不管是什么设备,都可以通过浏览器来查看Web页面。听起来很简单,对吧。从技术上讲,这并不完全准确。实际上,你可以通过浏览器的<code>viewport</code>查看Web页面。</p> <h3>Viewport</h3> <p><strong>Viewport</strong>指的是网页的显示区域,也就是不借助滚动条的情况下,用户可以看到的部分网页大小,中文译为“视窗”(或“视口”)。正常情况下,<code>viewport</code>和浏览器的显示窗口是一样大小的。但是,在移动设备上,两者可能不是一样大小。</p> <p>比如,手机浏览器的窗口宽度可能是<code>640px</code>,这时<code>viewport</code>宽度就是<code>640px</code>,但是网页宽度有<code>1200px</code>,正常情况下,浏览器会提供横向滚动条,让用户查看窗口容纳不下的<code>560px</code>。另一种方法则是,将<code>viewport</code>设成<code>1200px</code>,也就是说,浏览器的显示宽度还是<code>640px</code>,但是网页的显示区域达到<code>1200px</code>,整个网页缩小了,在浏览器中可以看清楚全貌。这样一来,手机浏览器就可以看到网页在桌面浏览器上的显示效果。</p> <p>简单点来说,视窗是指你的浏览器中实际用来显示网页的部分,比如像下图这样:</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-2.png" alt="" /></p> <p>拿Chrome浏览器来举例,<code>viewport</code>不包括浏览器的地址栏、状态栏或任何其他类型的用户界面。因为这些东西会占用空间。最后有一点很重要,<strong><code>viewport</code>也不包括滚动条占用的空间</strong>。</p> <p>言外之意,根据浏览器开启的不同设置(比如浏览器窗口状态栏、地址栏等),你的视窗大小将有所不同:</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-3.png" alt="" /></p> <p>正如前面提到的,<code>viewport</code>是可缩放的。既然可以缩放,那就具有可缩放的相关规则。在Web页面中,可以在HTML文件的<code>&lt;head&gt;</code>中像下面指定<code>viewport</code>相关的规则:</p> <pre><code>&lt;head&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/&gt; &lt;/head&gt; </code></pre> <p>上面代码指定,<code>viewport</code>的缩放规则是,缩放到当前设备的屏幕宽度(<code>device-width</code>),初始缩放比例(<code>initial-scale</code>)为<code>1</code>倍,禁止用户缩放(<code>user-scalable</code>)。</p> <p><code>viewport</code> 全部属性如下:</p> <ul> <li><code>width</code>: <code>viewport</code>的宽度</li> <li><code>height</code>: <code>viewport</code>的高度</li> <li><code>initial-scale</code>: <code>viewport</code>的初始缩放比例</li> <li><code>maximum-scale</code>: <code>viewport</code>的最大缩放比例</li> <li><code>minimum-scale</code>: <code>viewport</code>的最小缩放比例</li> <li><code>user-scalable</code>: <code>viewport</code>的是否允许用户缩放</li> </ul> <p>事实上,在JavaScript中,咱们测量<code>viewport</code>的大小也很容易。调用<code>document.documentElement</code>对象的<code>clientWidth</code>和<code>clientHeight</code>属性就可以测量出<code>viewport</code>的<code>width</code>和<code>height</code>。</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-4.png" alt="" /></p> <p>比如下面这个示例的代码,让你调整浏览器窗口大小时会更新<code>viewportWidth</code>(视窗宽度)和<code>viewportHeight</code>(视窗高度)两个变量的值:</p> <pre><code>let displayViewportSize = (e) =&gt; { let viewportWidth = document.documentElement.clientWidth let viewportHeight = document.documentElement.clientHeight console.log(`viewportWidth: ${viewportWidth},viewportHeight: ${viewportHeight}`) } window.addEventListener('resize', displayViewportSize, false) </code></pre> <p>运行上面的代码,随着你改变浏览器窗口大小时,将会输出更改后视窗<code>width</code>和<code>height</code>的值,如下所示:</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-5.png" alt="" /></p> <blockquote> <p>从《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/dom-tree-and-traversals.html">DOM树和遍历DOM</a>》一节中,我们知道<code>document.documentElement</code>是HTML的根元素,即<code>&lt;html&gt;</code>元素。<code>clientWidth</code>和<code>clientHeight</code>属性可以用来获取元素边框内区域的大小。也就是说,<code>document.documentElement.clientWidth</code>和<code>document.documentElement.clientHeight</code>分别获取的是<code>html</code>元素边框内区域的大小。如果你未接触过这两个属性,建议你花点时间阅读一下《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/get-element-position-and-size-using-javascript.html">获取元素位置和尺寸</a>》一文。</p> </blockquote> <p>如前所述,<code>viewport</code>的值不包括水平或垂直滚动条。但有时候,视窗大小的计算有可能也会包含滚动条的大小。如果计算的<code>viewport</code>大小包括了滚动条大小的话,咱们可以使用<code>window.innerWidth</code>和<code>window.innerHeight</code>来进行计算。</p> <blockquote> <p>注意,如果我们想测试整个浏览器的大小,那么可以使用<code>window.outerWidth</code>和<code>window.outerHeight</code>两个属性。它们返回浏览器窗口整个大小,包括浏览器的标题栏、状态栏等等。</p> </blockquote> <h2>测量屏幕分辨率和尺寸</h2> <p>JavaScript中除了测量浏览器和视窗大小的属性之外,还有其他度量大小的属性。比如测量屏幕分辨率和尺寸的属性:</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-6.png" alt="" /></p> <p>如果我们要测量屏幕的分辨率,可以使用下面这两对属性:</p> <ul> <li><code>window.screen.width</code> 和 <code>window.screen.height</code> 指的是显示器屏幕的宽度和高度,包括工具栏、状态栏等;</li> <li><code>window.screen.availWidth</code> 和 <code>window.screen.availHeight</code> 指的是浏览器窗口在屏幕上可占用的空间(宽度和高度)</li> </ul> <p><code>window.screen.width</code> 和 <code>window.screen.height</code>理论上返回的屏幕完整的分辨率:</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-7.png" alt="" /></p> <p>这两个属性没有考虑到屏幕(比如任务栏)占用的空间,所以它们不能准确地知道要处理多少像素。如果要知道屏幕实际有多大尺寸,应该使用<code>window.screen.availWidth</code> 和 <code>window.screen.availHeight</code>:</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-8.png" alt="" /></p> <p>这两对属性在JavaScript中可以像下面这样使用:</p> <pre><code>let displayScreenResolution = () =&gt; { let fullWidth = window.screen.width let fullHeight = window.screen.height let availableWidth = window.screen.availWidth let availableHeight = window.screen.availHeight console.log(`fullWidth: ${fullWidth}px; fullHeight: ${fullHeight}px; availableWidth: ${availableWidth}px; availableHeight: ${availableHeight}px`) } window.addEventListener('click', displayScreenResolution, false) </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-9.png" alt="" /></p> <h2>测量document的尺寸</h2> <p>接下来,咱们再来看看<code>document</code>文档尺寸的大小。</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-10.png" alt="" /></p> <p>可以通过<code>document.body</code>的<code>clientWidth</code>和<code>clientHeight</code>属性来获取文档的大小。从前面学习的知识中,我们知道<code>document.body</code>将获取的是<code>&lt;body&gt;</code>元素。</p> <p>如果我们想要获取文档<code>document</code>的<code>width</code>和<code>height</code>,我们可以像这样写:</p> <pre><code>let displayDocumentSize = () =&gt; { let docWidth = document.body.clientWidth let docHeight = document.body.clientHeight console.log(`Document's Width: ${docWidth}px; Document's Height: ${docHeight}px`) } </code></pre> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-11.png" alt="" /></p> <p><code>docWidth</code>和<code>docHeight</code>变量存储的是<code>document</code>的<code>width</code>和<code>height</code>。如果你的<code>document</code>(也就是<code>body</code>元素)用的是百分比设置单位,你将看到你的文档的大小会根据视窗的大小变更。</p> <p>比如,<code>body</code>设置样式:</p> <pre><code>body { width: 50%; height: 50%; } </code></pre> <p>运行<code>displayDocumentSize()</code>函数之后,缩放浏览器,那么返回的<code>docWidth</code>和<code>docHeight</code>也会随之变化:</p> <p><img src="/sites/default/files/blogs/2018/1807/viewport-device-scroll-document-size-12.png" alt="" /></p> <p>理论上,根文档元素是<code>documentElement</code>,也就是对应的<code>&lt;html&gt;</code>元素。而<code>documentElement.clientWidth</code>和<code>documentElement.clientHeight</code>分别获取的是浏览器可视区域的<code>width</code>和<code>height</code>。它包含了所有的内容,我们可以使用<code>documentElement.scrollWidth</code>和<code>documentElement.scrollHeight</code>来测量它完整尺寸。</p> <p>这些属性对于常规元素很有效。但是对于整个页面来说,这些属性并不能正常工作。在Chrome、Safari和Opera浏览器中,如果没有滚动条,那么就使用<code>documentElement.scrollHeight</code>,其获取的值甚至要比<code>documentElement.clientHeight</code>小。但对于常规元素来说,这是无稽之谈。</p> <p>那么要得到一个可靠的窗口大小,我们应该这样使用:</p> <pre><code>let scrollHeight = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ); </code></pre> <h2>滚动条尺寸</h2> <p>与滚动<code>scroll</code>相关的方法主要有<code>window</code>对象下的<code>scrollX</code>、<code>scrollY</code>、<code>scrollTo</code>和<code>scroll</code>;<code>Element</code>对象下的<code>scrollWidth</code>、<code>scrollHeight</code>、<code>scrollLeft</code>和<code>scrollTop</code>。</p> <blockquote> <p>有关于滚动条相关的API介绍,可以阅读<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/540.html">JavaScript学习笔记系列中</a>的《<" href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/offset-scroll-client.html">视口宽高、位置与滚动高度</a>》一文。</p> </blockquote> <p>有一点需要注意,大多数浏览器中可以使用<code>documentElement.scrollLeft</code>和<code>documentElement.scrollTop</code>来获取文档滚动条,但Chrome、Safari和Opera存有bug(比如<a href="http://xxysy.com/quot;//code.google.com/p/chromium/issues/detail?id=157855">157855</a>、<" href="http://xxysy.com/quot;//bugs.webkit.org/show_bug.cgi?id=106133">106133</a>)。如此一来,我们应该使用<code>document.body</code>来替代<code>document.documentElement</code>。</p>" <p>幸运的是,在JavaScript中有两个特殊属性:</p> <ul> <li><code>window.pageXOffset</code>:是<code>scrollX</code>的别名,返回文档/页面水平方向滚动的像素值</li> <li><code>window.pageYOffset</code>:是<code>scrollY</code>的别名,返回文档在垂直方向已滚动的像素值</li> </ul> <p>注意,这两个属性是只读属性,不能修改。</p> <p>除了上述提到的有关于滚动条的属性之外,还有<code>window.scrollTo()</code>,<code>window.scroll()</code>和<code>window.scrollBy()</code>等属性。</p> <p><code>window.scrollTo</code>方法用于将文档滚动到指定位置。它接受两个参数,表示滚动后位于窗口左上角的页面坐标。</p> <pre><code>window.scrollTo(x-coord, y-coord) </code></pre> <p>它也可以接受一个配置对象作为参数。</p> <pre><code>window.scrollTo(options) </code></pre> <p>配置对象<code>options</code>有三个属性:</p> <ul> <li><code>top</code>:滚动后页面左上角的垂直坐标,即 <code>y</code> 坐标</li> <li><code>left</code>:滚动后页面左上角的水平坐标,即 <code>x</code> 坐标</li> <li><code>behavior</code>:字符串,表示滚动的方式,有三个可能值(<code>smooth</code>、<code>instant</code>、<code>auto</code>),默认值为<code>auto</code></li> </ul> <p>我们使用的时候可以像下面这样使用:</p> <pre><code>window.scrollTo({ top: 1000, behavior: 'smooth' }); </code></pre> <p><code>window.scroll()</code>方法是<code>window.scrollTo()</code>方法的别名。</p> <p><code>window.scrollBy()</code>方法用于将网页滚动指定距离(单位像素)。它接受两个参数:水平向右滚动的像素,垂直向下滚动的像素。</p> <pre><code>window.scrollBy(0, window.innerHeight) </code></pre> <p>上面代码用于将网页向下滚动一屏。</p> <p>如果不是要滚动整个文档,而是要滚动某个元素,可以使用下面三个属性和方法。</p> <ul> <li><code>Element.scrollTop</code></li> <li><code>Element.scrollLeft</code></li> <li><code>Element.scrollIntoView()</code></li> </ul> <p>其中<code>scrollIntoView()</code>是HTML5新增的一个功能:<strong>元素滚动的API</strong>,功能是类似于锚点。</p> <blockquote> <p>根据 <a href="http://xxysy.com/quot;//developer.mozilla.org/zh-CN/docs/Web/API/Element/scrollIntoView">MDN</a>的描述,<code>Element.scrollIntoView()</code>方法让当前的元素滚动到浏览器窗口的可视区域内。</p>" </blockquote> <p><code>Element.scrollIntoView()</code>方法还有一个变体,即:<code>Element.scrollIntoViewIfNeeded()</code>。该方法也是用来将不在浏览器窗口的可见区域内的元素滚动到浏览器窗口的可见区域。但如果该元素已经在浏览器窗口的可见区域内,则不会发生滚动。</p> <p>有关于<code>scrollIntoView</code> 与 <code>scrollIntoViewIfNeeded</code>的 API 介绍,这里不深入下去。如果感兴趣的话,<a href="http://xxysy.com/quot;//juejin.im/post/59d74afe5188257e8267b03f">可以阅读这篇文章</a>。</p>" <h2>总结</h2> <p>在《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/get-element-position-and-size-using-javascript.html">获取元素位置和尺寸</a>》和《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/offset-scroll-client.html">视口宽高、位置与滚动高度</a>》两篇文章都有涉及JavaScript对视窗、滚动条、文档、元素大小尺寸相关的属性。由于自己是JavaScript的初学者,整理的相关学习笔记有点零乱。最后在这里简单的撸一下他们之间的关系。</p> <table> <thead> <tr> <th>属性名称</th> <th>描述</th> <th>备注</th> </tr> </thead> <tbody> <tr> <td><code>offsetParent</code></td> <td>返回一个指向最近的(closest,指包含层级上的最近)包含该元素的定位元素</td> <td>可以使用offsetParent获取最近的CSS位置(CSS-Positioned)的祖先</td> </tr> <tr> <td><code>offsetLeft</code></td> <td>当前元素左上角相对于<code>offsetParent</code>节点的左边界偏移的像素值</td> <td>&nbsp;</td> </tr> <tr> <td><code>offsetTop</code></td> <td>当前元素相对于其 <code>offsetParent</code> 元素的顶部的距离</td> <td>&nbsp;</td> </tr> <tr> <td><code>offsetWidth</code></td> <td>一个元素的布局宽度</td> <td>测量包含元素的边框、水平线上的内边距、竖直方向滚动条以及CSS设置的宽度的值</td> </tr> <tr> <td><code>offsetHeight</code></td> <td>元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数</td> <td>&nbsp;</td> </tr> <tr> <td><code>clientTop/Left</code></td> <td>返回该方向的<code>border</code>宽度</td> <td>该属性不包含元素的<code>padding</code>或<code>margin</code></td> </tr> <tr> <td><code>clientWidth/Height</code></td> <td>获取元素边框内区域的大小</td> <td>包括了内容的宽度和<code>padding</code>,但不包含滚动条宽度</td> </tr> <tr> <td><code>scroll</code></td> <td>滚动窗口至文档中的特定位置</td> <td><code>window.scrollTo</code> 同样能高效地完成同样的任务</td> </tr> <tr> <td><code>scrollLeft</code></td> <td>读取或设置元素滚动条到元素左边的距离</td> <td>&nbsp;</td> </tr> <tr> <td><code>scrollTop</code></td> <td>获取或设置一个元素的内容垂直滚动的像素数</td> <td>&nbsp;</td> </tr> <tr> <td><code>scrollWidth</code></td> <td>返回该元素区域宽度和自身宽度中较大的一个</td> <td>&nbsp;</td> </tr> <tr> <td><code>scrollHeight</code></td> <td>返回该元素内容高度</td> <td>包括被<code>overflow</code>隐藏掉的部分,包含<code>padding</code>,但不包含<code>margin</code></td> </tr> <tr> <td><code>scrollX</code></td> <td>返回文档/页面水平方向滚动的像素值</td> <td><code>pageXOffset</code>是<code>scrollX</code>的别名</td> </tr> <tr> <td><code>scrollY</code></td> <td>返回文档在垂直方向已滚动的像素值</td> <td><code>pageYOffset</code>是 <code>scrollY</code> 的别名</td> </tr> <tr> <td><code>window.innerHeight</code></td> <td>浏览器窗口高度,如果存在水平滚动条,则包括滚动条</td> <td>&nbsp;</td> </tr> <tr> <td><code>window.outerHeight</code></td> <td>浏览器窗口整个高度,包括窗口标题、工具栏、状态栏等</td> <td>&nbsp;</td> </tr> <tr> <td><code>window.innerWidth</code></td> <td>浏览器窗口宽度,如果存在垂直滚动条,则包括滚动条</td> <td>&nbsp;</td> </tr> <tr> <td><code>window.outerWidth</code></td> <td>浏览器窗口整个宽度,包括侧边栏,窗口镶边和调正窗口大小的边框</td> <td>&nbsp;</td> </tr> </tbody> </table> <h2>扩展阅读</h2> <ul> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/663.html">DOM系列</a>的<" href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/get-element-position-and-size-using-javascript.html">获取元素位置和尺寸</a></li> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/540.html">JavaScript学习笔记</a>系列的<" href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/offset-scroll-client.html">视口宽高、位置与滚动高度</a></li> <li><a href="http://xxysy.com/quot;//www.zhangxinxu.com/wordpress/?p=1907">CSSOM视图模式(CSSO" View Module)相关整理</a></li> <li><a href="//javascript.ruanyifeng.com/bom/window.html"><code>window</code>对象</a></li> <li><a href="http://xxysy.com/quot;//juejin.im/post/59d74afe5188257e8267b03f"><code>scrollIntoView</code>" 与 <code>scrollIntoViewIfNeeded</code> API 介绍</a></li> <li><a href="//javascript.info/size-and-scroll-window">Window sizes and scrolling</a></li> <li><a href="http://xxysy.com/quot;//www.kirupa.com/html5/viewport_device_document_size.htm">Viewport" Device, and Document Size</a></li> </ul> <p>如果文章中有不对之处,烦请路过的大婶拍正。如果这篇文章对您有所帮助,路过的大爷可以打个赏,让我有更大的动力去创作更多有用的伟德1946网页版。(^_^)</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/viewport-device-scroll-document-size.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/viewport-device-scroll-document-size.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/660.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/663.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DOM系列</a></div></div></div> Wed, 04 Jul 2018 14:17:38 +0000 Airen 2425 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com