响应式设计之媒介查询

Posted liuhe688

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了响应式设计之媒介查询相关的知识,希望对你有一定的参考价值。

你必须像水那样无形:当你把水倒进杯子中,水就变成了杯子的形状;当你把水倒进瓶子中,水就变成了瓶子的形状;当你把水倒进茶壶中,水就变成了茶壶的形状。 — 李小龙
之前读《响应式Web设计实践》,这大概是我印象最深的一句话了。李小龙的功夫了得,可他的功夫哲学更是令人叹服。如今的前端,面临着更多的挑战,尺寸大小不一的设备涌现出来,就像形状各异的容器,而我们的网页必须像水一般, 能够接受各式各样的考验。
为了能够让同一个页面在不同尺寸的设备浏览器中呈现出与之适配的样式,CSS3引入了Media queries,也就是媒介查询,通过一些条件询问语句声明和样式的定义,使浏览器能够应用那些与当前设备匹配的样式。
我们先来介绍一下媒介查询的一般结构:

@media [not | only] mediaType [and] (condition) {
    /* styles */
    a {
        /* styles applied on tag <a> */
    }
}

媒介查询以@media开头,然后可以使用not|only|and这些逻辑关键字把媒介类型条件表达式串联起来,去询问浏览器,此次声明的表达式是否满足当前运行环境,如果满足,则上面的styles部分的样式就会起作用,进而改变页面元素的样式。下面我们就来介绍和分析一下这个结构:

媒介类型

媒介是用来表示Web的呈现方式,我们的页面有可能被会打印出来,也有可能在投影仪中投射出来,或者在电视等平台中运行,所以也存在很多的媒介类型。以下是常用的媒介类型:

all: 所有设备(默认值)
handheld: 手持设备
print: 打印或打印预览
projection: 投影仪
screen: 彩色计算机屏幕
tv: 电视机

虽然上面列举的比较多,但实际上我们几乎只是用到了allscreenprint,因为现在很多显示设备,如手持设备,都已支持screen类型了。
在开发中,如果我们只是想为普通页面显示设置样式,则可以使用screen,如果想在打印时为页面重新设置一套样式,则可以使用print,如果定义的样式在所有模式下都希望生效,则可以使用all,就像下面这样:

@media screen {
    /* styles */
}
@media print {
    /* styles */
}
@media all {
    /* styles */
}

条件表达式

上面的媒介类型只能识别显示设备的类型,我们还需要针对特定的运行设备监测一些环境参数,比如长宽或分辨率等,下面列举了一些常用的参数:

width: 设备显示区域宽度
height: 设备显示区域高度
orientation: 设备的方向,portraitlandscape分别表示竖直水平
resolution: 设备的分辨率,以dpi(Dots Per Inch)或者dpcm(Dots Per Centimeter)表示

这几个属性中,最常用的就属width了,在使用时也可以加上min-max-前缀,组成更多的条件表达式。下面这几个查询就是width的应用:

@media screen and (width: 320px) {
    /* styles adapted to devices which (width == 320px) */
}
@media screen and (min-width: 320px) {
    /* styles adapted to devices which (width >= 320px) */
}
@media screen and (max-width: 960px) {
    /* styles adapted to devices which (width <= 960px) */
}

如代码所示,上面的三个表达是分别表示匹配宽度正好等于320px的情况匹配宽度大于等于320px的情况匹配宽度小于等于960px的情况,实际开发中我们可根据设计需要声明相对应的查询条件。除了px之外,我们也可以使用emrem来表示匹配的宽度。
在上面的代码中,我们使用了一个and逻辑关键字将前后的表达式连接起来,这是很常见的用法,另外还有notonly。其中not用于对整个表达式的结果取反,如果我们希望匹配320px及以下宽度的设备,下面两个表达式是等效的:

@media screen and (max-width: 320px) {
    /* styles */
}
@media not screen and (min-width: 320px) {
    /* styles */
}

only用于兼容老版本的浏览器。对于老版本的浏览器,是不支持媒介查询的,但也会尝试下载这些样式,这时候我们可以使用only关键字,对老版本的浏览器隐藏媒介查询,使之忽略这些样式,而对于那些高版本的浏览器,则会继续处理带有only关键字的查询语句,使用时就像下面这样声明:

@media only screen and (min-width: 320px) {
    /* styles */
}

另外还存在一个类似or的逻辑,如果希望在多个查询中只要存在有匹配的语句就去应用指定的样式,我们可以使用逗号来表示,这跟普通CSS代码中的使用方式是一样的:

@media screen and (min-width: 320px), @media print {
    /* styles */
}

内嵌样式和外联样式

上面介绍了媒介查询的基本语法和使用方式,下面我们接着了解一下两种不同的引入方式,即内嵌外联
内嵌样式比较简单,直接把媒介查询的样式和通用样式写在一起,比如我们要在宽度超过1280px的情况下为链接加上下划线,可以像下面这样:

a {
    text-decoration: none;
}
@media screen and (min-width: 1280px) {
    a {
        text-decoration: underline;
    }
}

这里注意,媒介查询需要声明在普通样式后面,下面这样声明将不会起作用:

@media screen and (min-width: 1280px) {
    /* will not take affect */
    a {
        text-decoration: underline;
    }
}
a {
    text-decoration: none;
}

外联样式和引入外部CSS文件相似,都使用link标签,不同的是,我们需要加上media属性:

<link href="style-big-screen.css" media="only screen and (min-width: 1280px)"/>

如果使用这种方式,那么在style-big-screen.css中,我们就可以直接声明CSS样式了:

a {
    text-decoration: underline;
}

外联和内嵌比较来看,代码更加清晰,利于开发和维护,但会增加额外的HTTP请求,实际开发中可依情况而定。

上面就是对媒介查询的介绍,接下来我们使用一个案例来演示一下如何在开发中应用媒介查询,为我们的应用添加响应式布局的功能。
在建立响应式页面时,有两种不同的思想,第一种是从桌面端开始向下设计,第二种是从移动端开始向上设计,前者默认是以桌面端为主,添加一些媒介查询来兼容移动端设备,而后者正好相反,从移动端开始逐步向桌面端适配,这也是比较推崇的一种做法,先创建核心体验,再一步一步为大屏幕设备添加复杂的布局。
我们先来使用流动式布局创建核心体验,下面是基本的html和CSS:

<html>
    <head>
        <title>Responsive</title>
        <meta name="viewport" content="width=device-width"/>
        <link rel="stylesheet" type="text/css" href="css/main.css">
        <script type="text/javascript" src="js/main.js"></script>
    </head>
    <body>
        <header id="page-header" class="clearfix">
            <h3>Responsive</h3>
            <ul class="nav-menu">
                <li>Home</li>
                <li>Blog</li>
                <li>Shop</li>
                <li>Jobs</li>
                <li>About</li>
            </ul>
            <div class="menu-btn" onclick="toggleMenu()"></div>
        </header>

        <section id="main-area" class="clearfix">
          <article class="clearfix">
            <header>The race to the moon is underway as Astrobotic raises $2.5 million</header>
            <img src="img/lander.jpeg"/>
            <p>
            Astrobotic Technology, the company that plans to deliver payloads to the moon, has completed a $2.5 million seed round led by Space Angels Network.
            </p>
            <!-- paragraph -->      
            <p>
            </p>
          </article>

          <aside>
            <h3>Related links:</h3>
            <ul>
                <li>
                    <a href="#">The Disrupt NY 2016 Hackathon Kicks Off</a>
                </li>
                <li>
                    <a href="#">The Blockchain is the new Google</a>
                </li>
                <li>
                    <a href="#">Google is reportedly announcing a standalone android VR headset next week</a>
                </li>
                <li>
                    <a href="#">Dismissing the cord-cutter myth</a>
                </li>
            </ul>
          </aside>

        </section>

    </body>
</html>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
ul, li {
    list-style: none;
}

.clearfix:after {
  content: ".";
  display: block;
  height: 0;
  clear: both;
  visibility: hidden;
}

#page-header {
    color: white;
    background-color: #2185D0;
}
#page-header h3,
#page-header .nav-menu {
    line-height: 40px;
}
#page-header .nav-menu {
    border-left: 1px solid white;
}
#page-header .nav-menu li {
    padding: 0 10px;
    cursor: pointer;
}
#page-header .nav-menu li:hover {
    background-color: #1EA83E;
}
#page-header .nav-menu.closed {
    display: none;
}
#page-header .menu-btn {
    position: absolute;
    top: 0;
    right: 10px;
    width: 40px;
    height: 40px;
    cursor: pointer;
    background: url(../svg/menu.svg) 50% 50% no-repeat;
}

#main-area article header {
    font-size: 25px;
    font-weight: bold;
}
#main-area article img {
    width: 100%;
}
#main-area article p {
    font-size: 18px;
    margin-bottom: 1em;
    padding: 0 2px;
}
#main-area aside {
    padding-left: 2px;
}

效果如图所示:

可以看到,这是个典型的移动端应用视图,点击右边的burger menu可以打开或关闭导航菜单:

function toggleMenu() {
    var nav = document.querySelector('#page-header .nav-menu');
    var isMenuOpen = nav.classList.contains('closed');
    var operation = isMenuOpen ? 'remove' : 'add';
    nav.classList[operation]('closed');
}

接下来我们需要考虑为稍微大一些的屏幕设计视图,将导航放到header上并隐藏burger menu,文章部分使文字部分环绕图片,这部分的样式代码如下:

@media screen and (min-width: 640px) {
    #page-header {
        padding: 0 2px;
        height: 40px;
    }

    #page-header .menu-btn {
        display: none;
    }

    #page-header h3,
    #page-header .nav-menu {
        float: left;
    }

    #page-header .nav-menu {
        display: block !important;
        margin-left: 10px;
    }

    #page-header .nav-menu li {
        float: left;
    }

    #main-area article img {
        float: left;
        width: 40%;
        padding: 2px;
        margin-right: 10px;
    }
}

页面布局如下图所示:

最后我们还需要考虑大屏幕的情况,大家注意到前面HTML部分最后那部分了吗,是一些相关的文章链接,它们在大屏幕下面将会显示到屏幕的右边,我们为此写一些样式:

@media screen and (min-width: 1280px) {
    #main-area article,
    #main-area aside {
        float: left;
    }
    #main-area article {
        width: 75%;
    }
    #main-area aside {
        width: 25%;
        margin-top: 25px;
        padding-right: 10px;
    }
    #main-area aside h3 {
        border-bottom: 1px dotted gray;
    }
    #main-area aside ul {
        margin-top: 10px;
    }
    #main-area aside li {
        padding: 10px 0;
        border-bottom: 1px dotted gray;
    }
    #main-area aside a {
        text-decoration: none;
    }
}

最终的效果如下图:

实际开发当中可能会遇到更加复杂的应用场景,只要灵活运用媒介查询,我们的应用便可以适配各种尺寸的设备。
关于响应式设计的媒介查询,今天就先介绍到这里了。

以上是关于响应式设计之媒介查询的主要内容,如果未能解决你的问题,请参考以下文章

响应式布局

响应式设计与自适应设计

网页设计中响应式具体怎么实现?

原理+实战 快速掌握响应式开发

原理+实战 快速掌握响应式开发精髓

响应式布局之媒体查询功能