如何在限宽的容器中实现全屏效果
ri15gf09
8年前
<p>在Web布局中,特别是在PC端中,常常可以看到这样的设计风格: <strong>内容居中,然后Banner区全屏</strong> 。这也就是标题所说的效果,限宽的容器中实现全屏效果。那么问题来了,在实际中如何实现在限宽的容器中实现全屏效果。比如下面的设计风格:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/17c4b7583eef89e674590ece3c9db6fa.png"></p> <p>作为一名前端开发人员,上图的效果并不陌生。假设我们内容区域是 960px ,然后水平居中。而其中Banner区域是全屏效果。如下所示:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/1f715b9c1a68b0ab4621b30bb224a5ad.png"></p> <p>那么实际开发中以什么方式来做更为方便灵活呢?这就是这篇文章需要介绍的内容。</p> <h2>页面结构</h2> <p>针对这样的设计风格,前端人员考虑的结构会有:</p> <pre> <code class="language-css"><div class="header"> <div class="container"></div> </div> <div class="banner"> <div class="container"> <img src="" alt=""> </div> </div> ...</code></pre> <p>这种结构要实现上述的需求,并不复杂。</p> <pre> <code class="language-css">.container { width: 960px; margin-left: auto; margin-right: auto; } .banner .container { width: 100%; } .banner img { width: 100%; max-width: 100% }</code></pre> <p>但很多时候,全屏图片的效果并不仅仅是在Banner区域。比如说在文章中插入的图片也需要全屏效果。那么针对上面的结构,咱们就有点蛋疼了。比如:</p> <pre> <code class="language-css"><div class="main"> <div class="container"> <p>....</p> <figure class="full-width"> <img src="" alt=""> </figure> <p>...</p> </div> </div></code></pre> <p>这才是问题的关键,如何让 .full-width 中的 img 能实现全屏的效果。正如文章开头的示意效果图。</p> <h2>CSS解决方案</h2> <p>针对上面描述的情况,首先能考虑到的方案就是采用我们常能看到的水平居中的一个效果。比如我们有一个元素(元素大小未知),要其水平居中。首先想到的是:</p> <pre> <code class="language-css">.full-width{ position: absolute; left: 50%; transform: translateX(-50%); }</code></pre> <p>在此思路上进行一下扩展。 .full-width 容器宽度是浏览器全屏宽度,在你脑海中立马浮现的是 100% ,但问题是,该元素是放置在 .container 容器中,而它的宽度又是 960px 。如果仅仅在 .full-width 上设置 100% ,那它的宽度并不等于浏览器视窗的全屏宽度,而是一个 960px 。如此一来,并不是我们想要的效果。</p> <p>既然如此,有什么方法可以让 .full-width 的宽度是浏览器视窗的全屏宽度。给大家推荐一个视窗单位 vw 。在这种情况下,视窗,指的是浏览器屏幕。 1vw 就意味着 1% 的浏览器的宽度。 100vw 将意味着整个浏览器宽度。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/2bb9efd2a13fe6ce566a20f51b927840.png"></p> <p>如此一来, .full-width 要拿到浏览器全屏的宽度就很容易了。只需要设置其 width 值为 100vw 。要实现文章开头示意的效果,有一个这样的思路。那就是把 .full-width 容器向右推 50% ,然后使用 margin-left: -50vw 拉回去。以同样的原理,把容器向左推 50% ,并使用 margin-right: -50vw 向右拉出去。如此一来, .full-width 就占据浏览器全屏宽度。不过需要注意的是,这里不能使用 position:absolute; 。因为使用 absolute 会让容器脱离文档流,至于这个问题,只需要将其值换成 relative ,就搞定了。根据上述描述,其效果变化过程如下所示:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/5a7fa153ee75fce05d340c6359a7590a.gif"></p> <p>这样我们就可以这样来写样式:</p> <pre> <code class="language-css">.full-width { width: 100vw; position: relative; left: 50%; right: 50%; margin-left: -50vw; margin-right: -50vw; }</code></pre> <p>结过上面的处理,容器 .full-width 虽然其父容器有宽度限制水平居中,但经过上面的代码拉伸推移,就实现了容器的全屏效果。如下所示:</p> <p>.full-width 容器已实现在限制宽度的容器中实现浏览器全屏宽度的效果。如果里面有 img ,只需要添加下面的样式代码:</p> <pre> <code class="language-css">.full-width img { width: 100%; max-width: 100%; }</code></pre> <p>如此一来,实现的效果如下面录制的效果一样:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/0c67eb916c46983a8dcf87d5f4bd12a7.gif"></p> <p>再思考一下,是不是这样就完美了呢?或者说有没有别的方案。我还是想到了 transform 中的 translateX 。既然 left 和 right 推移能实现,那我们是不是也可以考虑使用 translateX 。那问题来了,应该向左拉多少才合适呢?</p> <p>简单分析一下,容器的宽度是 960px ,全屏的宽度是 100vw ,他们之间相差就是 960px - 100vw , 但我们只需要向左拉出其值的一半,也就是 (960px - 100vw) / 2 。知道原理就好办了,咱们借助CSS的 calc() 函数 ,就解决一切问题了。</p> <pre> <code class="language-css">.full-width { width: 100vw; transform: translateX(calc(( 960px - 100vw ) / 2)); }</code></pre> <p>在CSS中 translateX 可以实现拉伸效果。除此之外,在CSS中 margin-left 和 margin-right 取值为负值时,也一样能实现位置变化。这样我们的代码可以调整为:</p> <pre> <code class="language-css">.full-width { margin-left: calc( (960px - 100vw) / 2); margin-right: calc( (960px - 100vw) / 2); }</code></pre> <p>上面的代码,还可以优化一下。 960px 相当于 100% ,这样一来 960px / 2 也就相当于 50% ;对应的 100vw / 2 就变成了 50vw 。这样上面的代码就变成了:</p> <pre> <code class="language-css">.full-width { margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); }</code></pre> <p>效果如下:</p> <p>上面使用了三种CSS方案实现限制宽度实现全屏效果。</p> <h2>Sass改造</h2> <p>为了上面的方案可以在需要使用的时候可随时使用。我们可以通过CSS处理器,比如说Sass的混合宏对其进行封装。比如我们创建一个 full-width 的混合宏,并且给这个混合宏传递两个参数,第一是实现方案的类似 $support-type ,可以给他传递三个值:</p> <ul> <li>margin :对应CSS中 margin-left 和 margin-right 的方案</li> <li>position : 对应CSS中 position 定位的方案</li> <li>translate : 对应CSS中 translateX 的方案</li> </ul> <p>并且给 $support-type 一个默认值,那就是 margin 。另外在给 full-width 传递一个 $min-width 的参数,其参数值默认设置为 null 。其在实际调用的时候,就是对应其容器的宽度值。比如前面示例中所演示的 960px 。</p> <p>针对上述描述,采用Sass的 @if 打件控制来做一个判断,最终我们需要的混合宏如下所示:</p> <pre> <code class="language-css">@mixin full-width($support-type: margin,$min-width:null){ @if $support-type == 'margin' { margin-left: calc(-50vw + 50%); margin-right: calc(-50vw + 50%); // margin-left: calc(-100vw / 2 + #{$min-width} / 2); // margin-right: calc(-100vw / 2 + #{$min-width} / 2); } @if $support-type == 'position' { width: 100vw; position: relative; left: 50%; right: 50%; margin-left: -50vw; margin-right: -50vw; } @if $support-type == 'translate' { width: 100vw; transform: translateX(calc((#{$min-width} - 100vw)/2)); } }</code></pre> <p>有了上述定义的混合宏,在实际使用的时候,只需要向下面这样调用:</p> <pre> <code class="language-css">.full-width { @include full-width(margin,960px); }</code></pre> <p>最终我们的效果如文章开头的示意图:</p> <p>在调用 full-width 混合宏的时候,你只需要改变其第一个参数,就能选择对应的实现方案。感兴趣的可以去尝试一下。</p> <p>在平时工作或者学习的过程中,你可以像这篇文章介绍的一样,不断的积累一些实用的Sass混合宏。如果你感兴趣的话,你可以下载Sass的混合宏和函数集合: <strong> SassMagic </strong> 。</p> <h2>总结</h2> <p>在限宽的容器中实现全屏效果可以说在Web设计中是非常常见的。这篇文章通过CSS使用了三种不同的方案实现了我们想要的效果,最后使用Sass的混合宏将CSS中介绍的三种方案集合在一起。在实际项目中可以通过调用参数,采取对应的CSS解决方案。让你的操作变得更为简便。</p> <p> </p> <p>来自:http://www.w3cplus.com/css/full-width-containers-limited-width-parents.html</p> <p> </p>