让浏览者禁用响应式布局界面

  • 原文:Letting users disable responsive layout
  • 作者:456 Berea Street 翻译者:潜行者m
  • 版权声明:版权归原作者所有,翻译仅作学习交流目的!
    响应式网站设计(Responsive Web Design)使用强大的媒体查询(media querie)让网站可以根据浏览者的浏览设备分辨率进行样式调整。但是,这样也产生了一个问题:有些人并不希望网站的外观在不同的浏览设备中发生改变。因为改变了之后,可能会让人产生疑问,认为自己在访问另一个网站。

虽然我不认为这会影响一大批人,但是绝大多数人肯定不懂响应式网站设计。如果有个人在电脑、平板电脑或者智能手机上访问同一个网站结果发现外观效果不同,他可能会感到很困惑。Bruce Lawson 在文章 Turning off responsive web design 中就提到了一个真实的例子。

一个同事也提到了另一个案例,响应式布局并没有很完美的客户端支持。客户经常提到布局问题等等。试想一下,如果你收到了一个邮件提到的是关于你用电脑访问看到的外观或内容,那么你用平板或者智能手机可能看不到相同的外观或者内容。当然,这种情况可能不多,但是这时候如果有一个可以切换或者关掉响应式布局的功能就好多了。

尽管这个功能不会让很多人受益,但是做这么个功能也并不是很复杂的事情。所以我在一些项目中增加了这个功能,现在想跟大家分享一下。这个方法跟 Adrian Roselli 写的 Letting Mobile Users See Desktop View of RWD Site 这篇文章中的很相似。这个功能不是很复杂,更不是什么革命性的改进,但是可以通过很多方法来实现。

如何命名响应式布局开关

有必要讨论一下怎么在网页中称呼这个功能。通常的名字是:查看桌面版布局、桌面版、完整版。而我称呼它为:查看固定宽度下的布局(当切换之后变成“查看弹性宽度下的布局”)。我并不确定这样可以帮助用户明白之间的异同,但是我认为这比起“桌面端”和“手机端”来说,描述的更加准确。有些人的浏览器窗口可能比 960px 还窄,也可能比 1200px 窄,或者是他们自己拖动设置的大小,虽然满足了媒体查询中定义的宽度,但是能在网页中显示“切换成桌面版”?

HTML 和 CSS 代码

我做了一个 Disable responsive layout 演示页面来展示效果。如果你打开了这个页面,并且调整你的浏览器窗口小于 960px ,一个就跟超链接似的开关就会显示出来,点击就可以切换。我觉得只有在媒体查询工作的时候才显示这个切换开关——如果响应式布局没有被触发,那切换个毛啊。

我选择直接把这个切换链接写进 HTML 中,而不是使用 JavaScript 临时生成。这是因为我使用后台(可以是任何后台语言,本文中使用 PHP 做演示)来处理 cookie ,这样就可以记录你是否选择了禁用响应式布局。

在前面的 demo 页面中,写入了如下的 HTML 结构,你可以自己定义:

<div id="toggle">
    <a href="?fixedwidth=1">Switch to fixed width layout</a>
&lt;/div&gt;`</pre>
使用 CSS 让其隐藏,不要写进媒体查询中:
<pre>`#toggle {
    display:none;
}
.fixed #toggle {
    display:block;
}`</pre>
为了方便切换,我们增加了 fixed 类。这样切换的时候,只需要对 html 对象加上 fixed 类就可以了。如果 html 对象中有这个类,就说明用户已经禁用了响应式布局,所以需要显示开关,方便他们再次启用。

下面 CSS 片段包含进媒体查询中:
<pre>`@media only screen and (max-width:960px) {

    #toggle {
        display:block;
    }

}`</pre>
上面代码实现当宽度小于 960px 的时候,触发媒体查询功能显示这个开关。如果用户已经禁用了响应式布局,上面代码将不会被加载(实现方法见下文)。

如果你的媒体查询 CSS 文件没有在一个单独的文件,要实现这个功能,可能需要做的更多工作。你可以在媒体查询的规则前面加上前缀 html:not(.fixed) 或者不使用媒体查询创建单独的文件。

##  JavaScript 代码

如果媒体查询的 CSS 代码被禁用,你要确保与响应式布局无关的 JavaScript 和 CSS 代码也被禁用。为了达到这个目的,你可以将下面的脚本放在单独的文件中,你也可以使用这种方法处理对应的 CSS (使用 PHP 处理),不加载这个文件。如果你没有分割成单独的文件,那么就通过检查 HTML 元素中是否有 fixed 这个类名在启用响应式布局功能脚本:
<pre>`&lt;script&gt;
if ( !document.documentElement.className.match(/(\\s|^)fixed(\\s|$)/) ) {
    // Responsive scripts go here, likely with additional checks
    // for viewport width, media query support etc.
}
&lt;/script&gt;`</pre>

##  PHP 代码

在本文 Demo 中,我使用 PHP 来处理 cookie 和提供切换响应式布局的功能。你可以使用 JavaScript 来实现这样的功能,但是这样在禁用 JavaScript 的客户端无法生效。毕竟这不是很关键的功能,如果你选择使用 JavaScript 请记住如果客户端不支持 JavaScript 的时候,也要显示出一个可以看到的链接。

下面就是一个简单的 HTML 结构和必须的 PHP 代码:
<pre>`&lt;?php
    $fixedwidth = '';
    //检查是否有 $fixedwidth 这个变量,然后获取
    if ( isset($_GET['fixedwidth']) &amp;&amp; ($_GET['fixedwidth'] != "") ) {
        $fixedwidth = $_GET['fixedwidth'];
    }
    //检查是否有对应的 cookie 内容
    if ( isset($_COOKIE['fixedwidth']) ) {
        if ( $fixedwidth == '0' ) {
            // 如果值为 0 就清除 cookie
            setcookie('fixedwidth', '', time() - 60, '/');
        } else {
            // 如果值不为零,就获取
            $fixedwidth = '1';
        }
    } else if ( $fixedwidth == '1') {
        // 浏览者想要禁用响应式布局功能,设置一个 cookie
        $expires = 60 * 60 * 24 * 60 + time(); 
        setcookie('fixedwidth', '1', $expires, '/');
    }
?&gt;
&lt;!DOCTYPE html&gt;
&lt;html lang="en" &lt;?php if ($fixedwidth == '1') { echo 'class="fixed"'; } ?&gt;&gt;
&lt;head&gt;
    &lt;meta charset="utf-8" /&gt;
    &lt;title&gt;Document title&lt;/title&gt;
&lt;?php
// 只在响应式布局可用的时候插入 meta[name="viewport"] 对象
if ( $fixedwidth != '1' ): ?&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1" /&gt;
&lt;?php endif; ?&gt;
    &lt;link rel="stylesheet" href="main.css" /&gt;
&lt;?php
// 只在响应式布局可用的时候,插入 CSS 文件
if ( $fixedwidth != '1' ): ?&gt;
    &lt;link rel="stylesheet" href="mq.css" /&gt;
&lt;?php endif; ?&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Document title&lt;/h1&gt;
    &lt;div id="toggle"&gt;
&lt;?php
// Responsive is disabled, so insert a switch to flexible width
if ( $fixedwidth == '1' ): ?&gt;
        &lt;a href="&lt;?php echo $_SERVER["SCRIPT_NAME"] ?&gt;?fixedwidth=0"&gt;Switch to flexible width layout&lt;/a&gt;
&lt;?php
// Responsive is not disabled, so insert a switch to fixed width
else: ?&gt;
        &lt;a href="&lt;?php echo $_SERVER["SCRIPT_NAME"] ?&gt;?fixedwidth=1"&gt;Switch to fixed width layout&lt;/a&gt;
&lt;?php endif; ?&gt;
    &lt;/div&gt;
    &lt;script&gt;
    if ( !document.documentElement.className.match(/(\\s|^)fixed(\\s|$)/) ) {
        // Responsive scripts go here
    }
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

上面的 PHP 代码肯定能进一步改进,这里只是抛砖引玉给你一个思路,你可以自己编写更符合你要求的代码。

这个功能应该在客户端中吗?

你可能会产生浏览器是否应该增加切换响应式布局功能的疑问。浏览器可能需要禁止他们自身对媒体查询的支持,而是通过网站的设置来默认显示“全尺寸”或者“桌面版”。这就是为什么我个人喜好直接开发网站,但是其他开发者却相反的先使用媒体查询功能开发“手机端”的网站,然后再开发“桌面端”布局。

如果你使用媒体查询为老的浏览器隐藏 CSS3 的功能,这也会产生问题。一个浏览器的禁用媒体查询的功能,可能会禁用所有的媒体查询中的代码,这样会产生很多布局的问题。

所以,这个功能应该交给咱们 Web 开发者来做。如果你需要这个功能,上面提供了一个不错的思路。

译者总结

禁用响应式布局确实是一个必要的功能。Bruce Lawson 在 Turning off responsive web design 这篇文章中,提到了一个小故事。说他的父亲在用手机访问一个网站的时候,发现跟电脑访问时不一样,而怀疑自己是不是在访问想访问的网站,然后关掉了。

潜行者m 曾经使用平板和智能手机做过测试,虽然智能设备上的浏览器通常可以设置“使用什么样的客户端模式(桌面、手机)来访问网站”,但是响应式布局使用的媒体查询技术,直接根据设备的参数等进行改变,不会因为客户端的代理模式(User-Agent)。特别是使用手机想要看到网站的桌面版效果,就很难实现了。

通过 JavaScript 来实现这个功能也非常简单,但是使用 PHP 更加有优势。这样可以减少不必要的 CSS 、JS 文件的引入,增强前端性能。但是 PHP 的移植性不太好。所以也可以考虑使用 JavaScript 来实现。

如果想要你的网站更加完善,如果使用了响应式布局的设计,最好加上一个禁用选项。

使用 PHP 获取并解析 JSON 显示在页面中

很久没写过 PHP 的文章了,也很久没有用 PHP 了,差点忘了怎么做了。JSON 是现在比较流行的数据交流方式,比 XML 都流行,一般用作 api 接口进行数据获取、交流。

就文章的标题来说,本文介绍两个小要点:PHP 获取内容、PHP 解析 JSON 并显示。

PHP 获取接口内容

你如果想解析 JSON 数据并且显示在页面中,第一步肯定要先得到 JSON 接口文件的内容。在 PHP 中获取一个页面的内容,可以使用 fopen() 函数远程页面然后使用 fread() 函数循环获取内容。

假设接口文件页面为:http://www.qttc.net/api.php?action=open_getBlogList&only_recommend=1&limit=5 ,那么我们可以使用下面语句获取这个接口文件内容:

$handle = fopen("http://www.qttc.net/api.php?action=open_getBlogList&only_recommend=1&limit=5","rb");
$content = "";
while (!feof($handle)) {
    $content .= fread($handle, 10000);
}
fclose($handle);

这样 content 保存的就是 JSON api 内容。

PHP 解析 JSON 并显示

原始的内容是无法直接调用的,必须被 PHP 进行进一步处理,才能被调用显示在网页中。在 PHP 5.2 及后续版本中,使用 json_decode() 函数来解析 JSON 数据,将其转换成 PHP 可以调用的数据格式。例如:

$content = json_decode($content);

解析之后呢,我们就可以按照 PHP 中调用数组数据的方法一样的调用 JSON 中的数据。这个调用方法需要按照具体的 JSON 数据格式来写,演示请看下面。关于 json_decode 函数的使用,具体看 PHP 手册,这里不再赘述:http://php.net/manual/en/function.json-decode.php

实战调用琼台博客的 api

细心的朋友会发现 潜行者 m 博客的边栏最下面多了一个“友文推荐”模块,里面推荐了一些琼台博客的文章。

友文推荐

友文推荐是琼台博客倡议的一种博客之间交流方式,比传统的友情链接更有效,同时实现了博客内容互补。由于琼台博客的博客程序是他自己本人编写的,所以他提供了 JSON api 接口,可以获取到最新的可推荐的文章。

本人使用 PHP 获取这个 JSON 接口,然后输出到自己博客的边栏中,下面来实战操作一下。

第一步,查看 api 调用方式

调用之前,你肯定要看一下对方的 api 调用手册,包括调用地址、如何调用、数据输出格式等等。琼台博客的 api 说明地址如下:http://www.qttc.net/openapi.html

根据文档,我使用了 http://www.qttc.net/api.php?action=open_getBlogList&only_recommend=1&limit=5 这样的参数,意思就是调用五条他推荐的文章。

第二步,获取 api 结构数据

很简单,上面说过了,具体代码如下:

$handle = fopen("http://www.qttc.net/api.php?action=open_getBlogList&only_recommend=1&limit=5","rb");
$content = "";
while (!feof($handle)) {
    $content .= fread($handle, 10000);
}
fclose($handle);

先打开这数据文件,然后把所有内容保存到 content 变量中,因为可以肯定 api 数据不会超过 10000 个字符,所以用 10000 作为 fread 函数的第二个参数。这样,api 返回的 JSON 数据就保存在了 content 变量中。

第三步,解析并输出内容

使用下面代码解析数据,然后调用输出

$content = json_decode($content);
foreach ($content->data as $key) {
    echo '<li><a target="_blank" href="'.$key->b_url.'">'.$key->b_title.'</a></li>';
}

首先对 content 变量中的 JSON 数据处理,然后变成 PHP 可以调用的数据,再使用 foreach 遍历输出这五条内容,按照我需要的 HTML 格式,将内容插入进去即可。

再加上样式修饰,这样就完成了 获取并解析 JSON 显示在页面中了。调用其它 api 数据的方法大同小异。

Style.css文件生成工具

此工具正在升级,暂时无法使用看到,待升级完毕,会新发一篇文章!

工具地址:http://labs.qianxingzhem.com/app/csscreater

开发时间:2012-8-10

作者:潜行者m

在制作wordpress主题的时候,我们需要css文件,在标准的wordpress主题中,官方推荐将css文件命名为style.css

在使用主题的时候,我们可以上传安装主题,也可以在线安装。当我们安装好主题的时候,我们会发现会有作者、作者地址、模板介绍等等信息。这些信息是写在style.css文件里面的。只有按照正确的格式,写进style.css文件,我们才能把主题压缩成zip直接上传安装。

本工具的功能就是为了简化这个流程。你只需要填写一个表单,就可以自动生成带有正确格式信息的style.css文件。

当然,不仅仅是输出你输入的wordpress主题版权信息,在style.css文件里面,还附带了一段非常成熟的CSS reset 代码,将元素在不同浏览器中的不同表现一律抹平。如果你不知道为什么使用CSS reset,可以看一下潜行者m的这篇文章:网页设计为什么要使用css reset

同时,还附带了本人常用的css原子类,使用原子类,可以非常容易的进行布局等。关于为什么要使用原子类,可以看一下潜行者m的这篇文章:网页设计中构建并使用原子类

当然,还帮你整理好了结构,因为本人患有代码整理强迫症 ^_^

此外,这个工具也不仅仅可以用于wordpress,你在设计网页的时候,也需要在css文件里面,声明你的作品版权,这个工具就是为了帮助你省略这些工序。

解决iconv和mb_convert_encoding函数的汉字乱码问题

近期在做一个小应用,就是填上信息,然后输出wordpress模板标准的style.css文件,当然,这个文件包含了CSSreset 和本人常用的原子类,这样可以大大缩小制作的难度和时间。

于是就遇到了一个编码问题,因为wordpress的编码是UTF-8,所以我们模板的css文件编码最好也是UTF-8。因为在早期的浏览器中,如果编码和文档中声明的不同,会读取不出来。IE6就是这样,在其他浏览器中没有出现类似的情况,不过还是建议使用UTF-8编码,如果你的模板要面向全世界的用户,你必须用这个编码,因为国外的电脑上没有装GBK、GB2312这类中文编码,就会出现乱码,或者出现一些其他的意外情况。

那么,我使用php接受字符串,并且输出的时候,需要使用编码相关的函数。经过搜索,找到了标题上面的两款函数。iconv和mb_convert_encoding,这两个函数,可以把字符串进行编码,然后配合file_put_contents这个函数,可以输出你指定的编码。我这个工具的原理很简单,就是获取表单内容,读取已经保存的写好的文件,然后混合编码,输出。

$add_string = $add_string.$fpr; //$fpr变量是读取之前写好的UTF-8编码的style.css文件模板
$add_string = iconv(“utf-8”,”utf-8”,$add_string); //由于读取的style.css文件是utf-8编码,所以这里用了utf-8编码转换utf-8编码
file_put_contents($new_filename,$add_string);

但是问题就出现了,出现在中文上了。由于iconv是php默认安装的模块,所以先使用的iconv函数。编写完成之后,输入中文信息,输出中断,查看输出文件,在中文的地方,输出了一个DZ,之后就断掉了。经过搜索,说这是iconv的一个bug,遇到“-”这样的符号,就出问题,可以使用“GBK”编码或者是加上“//IGNORE”参数解决。实验了一下,还是没有效果,加上了//IGNORE参数,中文全被过滤,只输出英文。

疯狂的在网上查找相关资料,没有找到,我找了一段网上编写的,有这个函数的应用,把代码运行了一下,结果发现,还是没有。蛋碎,别人写的可以用的代码,在自己电脑上还是不能支持中文。我phpinfo了一下,这个模块正常啊,我还把代码上传到远程服务器上,执行还是不行。

没办法,我考虑使用同样的功能的mb_convert_encoding函数,来试一下。结果还是不行,仍然出现乱码。这个时候,我突然想,不要把utf-8转换成utf-8 了,把GBK转换成utf-8试试怎么样啊。试了一下,表单部分在utf-8文件中,显示正常,但是模板(style.css模板用的utf-8编码)中的中文,全都变乱码了。研究一晚上这个问题了,已经到了0点了,果断关机睡觉。

在床上,翻来覆去的思考这个问题。最后的这个尝试,给了我一个思路。然后我就想明白了,我们用浏览器输入内容,我们也没有规定编码是什么,那系统得到我们输入的内容,它的编码是什么呢?那就只有GB2312 了,因为我中文系统默认的编码就是这样。所以,我对字符串的处理,应该是由GBK、GB2312来转换成UTF-8编码才对。这就是为什么最后,表单内容正常,而源css模板不正常了。我用utf-8保存的css模板,却用GBK的方式去读,然后转换成utf-8编码,读出来的时候,已经是乱码了,再把乱码转换成utf-8,那不更乱了。

不仅感叹一句,有多少问题,是在床上解决的,别想歪了哦 ^-^

今天早上起来,立刻按照昨晚想的思路写了一下,果然可以成功输出汉字。最终代码:

    $add_string = iconv(“GBK”,”utf-8”,$add_string);//先把表单内容转成utf-8
$add_string = $add_string.$fpr; //再与utf-8编码的css模板文件结合
file_put_contents($new_filename,$add_string); //输出

就这样,变化一下顺序,这个问题就完美解决了。今天写这篇文章时,发现这是一个多么简单的逻辑问题,却研究尝试了一个晚上,自己也真够笨的。不过最终解决了就好。我们平时都看书,太重于理论,到实践的时候,却发现,出现好多书上没有的错误。但是有了这个经历,以后遇到编码问题,就再也不用怕了。

另附这两个函数的用法:

iconv(“UTF-8”,”GB2312//IGNORE”,$data); //意思是把$data字符串由utf-8编码转成gb2312编码,刚开始就被这个误导了

mb_convert_encoding($data, “UTF-8”, “GBK”); //这个意思是把$data字符串,由gbk转成utf-8编码,注意顺序与iconv相反

至于gbk和gb2312,都是中文编码,区别在于,你想多打字,就打gb232,想少打字就打gbk.

此外,上面这两个函数,需要配合file_put_contents这个函数输入才有效,这个函数的用法和其他输出函数都一样.不再赘述.