您的位置:澳门新葡8455最新网站 > Web前端 > 响应式加强布置

响应式加强布置

发布时间:2019-12-09 15:19编辑:Web前端浏览(118)

    响应式增强设计

    2015/03/18 · CSS, HTML5, JavaScript · 响应式, 设计

    本文由 伯乐在线 - fzr 翻译,黄利民 校稿。未经许可,禁止转载!
    英文出处:24ways.org。欢迎加入翻译组。

    24ways 在这10年中已经逐渐变得强大了。在因特网历史中这已是一个永远不可磨灭的了。回想一下在那段时间里我们见证所有变化:Ajax的兴起,移动设备的激增,前端开发工具不可预知的前景。

    工具和技术来来往往,兴起衰落,但在过去的十年中有一件事于我而言是一直没有变化的:渐进式增强。

    渐进式增强不是一门技术。它更像是一种思考方式。渐进式增强鼓励你去思考网页所提供的基本意义,而不是去想一个已完成网页如何展示的细小问题。所以渐进式增强允许你以更抽象的方式思考核心功能,而不是纠结于网页在不错的宽屏设备上的理想状态。

    一旦你已经确定要添加的核心功能是什么–向购物栏中添加一件商品,发布一条消息,分享一张图片–然后你可以以一种最简单的方式实现该功能。那通常也意味着要从优秀的老式的HTML入手。你所需要的通常只是链接和表格。然后,只要你已经使得该核心功能基本工作,你就可以开始对更多现代浏览器加强功能以逐步提供更好的用户体验。

    以这种方式工作的好处不仅仅是你的网页可以在旧式浏览器中工作(尽管只是基本能运行)。它还能保证如果在现在的浏览器中出现的小毛病不至于酿成大祸。

    人们对渐进式增强存在一个误解,认为渐进式增强就是花时间解决旧式浏览器,然而事实却相反。将基本功能投入使用并不会花费太久。而且一旦你已经完成这部分工作,你就可以随心所欲地去测试最新最好的浏览器技术,脑中的意识是即使它们现在还不能被普遍支持,也没有问题,因为你已经把最可靠的东西投入使用了。

    看待Web发展的关键在于意识到不会有最终的接口—可能会有很多只有轻微差别但会依赖于任意时刻任意用户的属性和容量的接口。网站不需要在每一个浏览器中都一模一样。

    真正理解了这个就是一个极大地进步。你可以把时间花费在为更多浏览器提供最好体验的同时保证能在任何建立工作的地方实现核心功能,而不是努力使你的网站在差异巨大的浏览器中一模一样。

    允许我以一个简单的例子来表述:导航。

    第一步:核心功能

    假设我们现在有一个关于圣诞节12天欢庆的简单网站,一天一个页面。这个核心功能也相当清晰了:

    1、了解其中任意一天。
    2、从一天到另一天浏览。

    第一个功能可以通过将文本用头条,段落以及所有常用的HTML结构化标签组装起来实现。第二个则通过一系列的超链接实现。
    那么现在导航列表最适合放在哪里呢?个人而言,我是一个跳转到页脚导航模式的粉丝。这个模式先放网页内容,其次才是导航。页面顶部有一个带有href属性的连接指向导航的标签。

    XHTML

    <a class="control" href="#menu">Menu</a> ... <nav id="menu" role="navigation">... <a class="control" href="#top">Dismiss</a></nav>

    1
    2
    3
    4
    5
    <a class="control" href="#menu">Menu</a>
    ...
     
    <nav id="menu" role="navigation">...
    <a class="control" href="#top">Dismiss</a></nav>

    查看页脚超链导航模式的演示。

    由于只有超链接,这个模式也只是在网络初兴时期能在每一个浏览器上工作。Web浏览器要做的只是展示超链接(正如名字所示)。

    第二步:增强型布局

    在小屏幕设备上,比如移动电话,页脚链接模式是一个相当简洁的解决办法。一旦有更多的屏幕空间可使用时,就可以使用CSS将导航重新定位在内容之上。我可以设置position属性为absolute,使用弹性布局盒,或者设置display属性为table。

    CSS

    @media all and (min-width: 35em) { .control { display: none; } body { display: table; } [role="navigation"] { display: table-caption; columns: 6 15em; } }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @media all and (min-width: 35em) {
      .control {
        display: none;
      }
      body {
        display: table;
      }
      [role="navigation"] {
        display: table-caption;
        columns: 6 15em;
      }
    }

    查看宽屏样式的演示。

    第三步:增强!

    没错。现在我已经可以为所有人提供核心功能了,而且对宽屏也有相当不错的响应风格设计。到这里我可以停下脚步了,但渐进式增强的实际优点却是我还没有做到的。从这儿开始,我可以疯狂地为现代浏览器添加各种奇特的优化效果,而不用担心不能为旧式浏览器提供退路—退路已经准备好了。

    实际上我想为小屏幕的设备提供一个漂亮的屏外画布。下面是我的规划:

    1、 将导航放置在主内容下面。
    2、 监听伪类为.control的链接是否被点击并拦截其反应。
    3、 当这些链接被点击后,为主体body切换赋予伪类.active。
    4、 如果伪类.active存在,将内容滑出以显示导航。

    下面是定位内容和导航的CSS代码:

    CSS

    @media all and (max-width: 35em) { [role="main"] { transition: all .25s; width: 100%; position: absolute; z-index: 2; top: 0; right: 0; } [role="navigation"] { width: 75%; position: absolute; z-index: 1; top: 0; right: 0; } .active [role="main"] { transform: translateX(-75%); } }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @media all and (max-width: 35em) {
      [role="main"] {
        transition: all .25s;
        width: 100%;
        position: absolute;
        z-index: 2;
        top: 0;
        right: 0;
      }
      [role="navigation"] {
        width: 75%;
        position: absolute;
        z-index: 1;
        top: 0;
        right: 0;
      }
      .active [role="main"] {
        transform: translateX(-75%);
      }
    }

    在我的JavaScript代码中,我将会监听伪类.control链接上的任何点击事件,然后据此为主体body切换赋予伪类.active。

    JavaScript

    (function (win, doc) { 'use strict'; var linkclass = 'control', activeclass = 'active', toggleClassName = function (element, toggleClass) { var reg = new RegExp('(s|^)' + toggleClass + '(s|$)'); if (!element.className.match(reg)) { element.className += ' ' + toggleClass; } else { element.className = element.className.replace(reg, ''); } }, navListener = function (ev) { ev = ev || win.event; var target = ev.target || ev.srcElement; if (target.className.indexOf(linkclass) !== -1) { ev.preventDefault(); toggleClassName(doc.body, activeclass); } }; doc.addEventListener('click', navListener, false); }(this, this.document));

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    (function (win, doc) {
      'use strict';
      var linkclass = 'control',
        activeclass = 'active',
        toggleClassName = function (element, toggleClass) {
          var reg = new RegExp('(s|^)' + toggleClass + '(s|$)');
          if (!element.className.match(reg)) {
            element.className += ' ' + toggleClass;
          } else {
            element.className = element.className.replace(reg, '');
          }
        },
        navListener = function (ev) {
          ev = ev || win.event;
          var target = ev.target || ev.srcElement;
          if (target.className.indexOf(linkclass) !== -1) {
            ev.preventDefault();
            toggleClassName(doc.body, activeclass);
          }
        };
      doc.addEventListener('click', navListener, false);
    }(this, this.document));

    我已经准备就绪了,是吗?哪有那么快!

    复制代码 代码如下:/*----------------------------------- Web Application JavaScript Library 2009.11 janchie ------------------------------------*/ //String原生对象扩展 置空左右端空格 String.prototype.trim = function(){ return this.replace|; }; //Date原生对象扩展 格式化输出 Date.prototype.format = function { var self = this; var p = function p { return .length == 1) ? "0" + s : s; }; return string ? string.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g, function { switch { case "hh": return p < 13 ? self.getHours - 12)); case "h": return self.getHours() < 13 ? self.getHours - 12); case "HH": return p; case "H": return self.getHours(); case "mm": return p; case "m": return self.getMinutes(); case "ss": return p; case "s": return self.getSeconds(); case "yyyy": return self.getFullYear(); case "yy": return self.getFullYear.substring; case "dddd": return self.getDayName(); case "ddd": return self.getDayName; case "dd": return p; case "d": return self.getDate; case "MMMM": return self.getMonthName(); case "MMM": return self.getMonthName; case "MM": return p); case "M": return self.getMonth() + 1; case "t": return self.getHours() < 12 ? Date.CultureInfo.amDesignator.substring : Date.CultureInfo.pmDesignator.substring; case "tt": return self.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator; case "zzz": case "zz": case "z": return ""; } }) : this.toString(); }; /*------------------------------------*/ //声明对象 var App = {}; //对象继承或属性合并 App.extend = function { this.each(hash, function { obj[key] = value; }); return obj; }; //遍历 App.each = function { var length = obj.length, i = -1; if { while if(func.call(context, obj[i], i, obj, length) === false) break; } else for if(obj.hasOwnProperty if(func.call(context, key, obj[key], obj) === false) break; return obj; }; { var string = Object.prototype.toString, quirks = doc.compatMode === "BackCompat", docelem = doc.documentElement, ua = win.navigator.userAgent.toLowerCase(), version = (ua.match[/: ][1], isChrome = /chrome/.test, isWebKit = /webkit/.test, isSafari = !isChrome && isWebKit, isOpera = /opera/.test, isIE = /msie/.test && !isOpera, isFF = /firefox/.test; //Dom加载 doc.ready = function { var isReady = false,doReady = function return; isReady = true; func { if (docelem.doScroll && win.self == win.top) { { if return; try { docelem.doScroll; } catch { setTimeout; return; } doReady; }else { if return; this.attachEvent("onreadystatechange", function() { if (doc.readyState === "complete") { doc.detachEvent("onreadystatechange", arguments.callee); doReady; } win.attachEvent; }else if (isWebKit && version < 525) { { if return; if (/loaded|complete/.test doReady(); else setTimeout; })(); win.addEventListener('load', doReady, false); }else { if this.addEventListener("DOMContentLoaded", function() { doc.removeEventListener("DOMContentLoaded", arguments.callee, false); doReady; this.addEventListener('load', doReady, false); } }; App.extend(App,{ //类型检测 isArray: function { //是否为数组 return string.apply === "[object Array]"; }, isFunction: function { //是否为函数体 return string.apply === "[object Function]"; }, isNumber: function { //是否为数字 return typeof v === "number" && isFinite; }, isDate: function { //是否为日期 return string.apply === "[object Date]"; }, isElement: function { //是否为Dom元素节点 return !!(v && v.nodeType === 1); }, // 浏览器检测 isOpera: isOpera, isChrome: isChrome, isWebKit: isWebKit, isSafari: isSafari, isIE: isIE, isFF: isFF, isQuirks:quirks, getVersion:version, //取id元素 $: function { return typeof id === "string" ? doc.getElementById : id; }, //取name元素集合 $N:function{ return doc.getElementsByName; }, //取tag元素集合 $T:function{ return .getElementsByTagName、值、范围取元素集合 $A:function(attrName, attrValue, tag, root){ var elems = doc.all ? doc.all : this.$T( tag || "*",root || doc), result = [], attVal = (typeof attrValue != "undefined")? new RegExp" + attrValue + " : null; for(var i=0; i 0){ if(typeof attrValue === "undefined" || (attVal && attVal.test{ result.push; } } } return result; }, //取body元素 $B: doc.body || docelem, //取Class属性元素集合 $C:function{ return this.$A("className",attrValue, tag, root); }, //取浏览器窗体宽度 getWinWidth: win.innerWidth || docelem.clientWidth || doc.body.clientWidth, //取浏览器窗体高度 getWinHeight: win.innerHeight || docelem.clientHeight || doc.body.clientHeight, //取元素样式 getStyle: function{ if{ return elem.style[name]; }else if{ return elem.currentStyle[name]; }else if(doc.defaultView && doc.defaultView.getComputedStyle){ name = name.replace; name = name.toLowerCase(); var s = doc.defaultView.getComputedStyle; return s && s.getPropertyValue; }else{ return null; } }, //获取元素屏幕坐标值 getPosition: function() { return docelem.getBoundingClientRect && function{ var pos = o.getBoundingClientRect(), root = o.ownerDocument || o.doc; return {left:pos.left+root.documentElement.scrollLeft,top:pos.top+root.documentElement.scrollTop}; } || function{ var x = 0, y = 0; do{x += o.offsetLeft;y += o.offsetTop;}while; return {left:x,top:y}; }; }(), //设置透明度 setOpacity: function { if{ elem.style.filter = "alpha"; }else{ elem.style.opacity = num/100; } }, //隐藏或显示元素 hide: function{elem.style.display = "none";}, show: function{elem.style.display = "block";}, toggle: function{ elem.style.display = this.getStyle === "none" ?"block":"none"; }, //元素Class属性操作 addClass: function { if (elem.className === '') { elem.className = clsName; }else if (elem.className !== '' && (' ' + elem.className + ' ').indexOf === -1) { elem.className = elem.className

    标准符合测试

    我假设在我的代码中已经实现addEventListener函数。这并不是一个安全的假设。因为JavaScript不像HTML或CSS那样具有容错性。如果你使用了一个浏览器不能识别的HTML元素或属性,或是使用了一个浏览器不能理解的CSS选择器,属性或是值,那都不是大问题。浏览器会忽略掉它不能识别的东西:既不会抛出错误也不会停止解析文件。

    JavaScript就不同了。如果你的JavaScript代码有错误,又或者使用了一个浏览器不能辨识的JavaScript函数或属性,浏览器会抛出错误,而且会停止解析文件。这就是为什么JavaScript中特征在使用之前必须要测试。这也说明将核心功能依赖于JavaScript是非常不安全的。

    就我而言,我需要测试addEventListener函数的存在性:

    JavaScript

    (function (win, doc) { if (!win.addEventListener) { return; } ... var enhanceclass = 'cutsthemustard'; doc.documentElement.className += ' ' + enhanceclass; }(this, this.document));

    1
    2
    3
    4
    5
    6
    7
    8
    (function (win, doc) {
      if (!win.addEventListener) {
        return;
      }
      ...
      var enhanceclass = 'cutsthemustard';
      doc.documentElement.className += ' ' + enhanceclass;
    }(this, this.document));

    BBC的大牛们称这种特征测试为标准符合测试。如果一个浏览器通过了该测试,它就达到了标准,所以它就获得了增强性能。如果一个浏览器没能达到标准,它就没有增强的性能。这也不算什么坏事,记住,网站不需要在每个浏览器中都表现的一样。

    我希望确保我的离线画布样式只能应用于符合标准的浏览器。我会使用JavaScript为文档添加一个伪类.cutsthemustard:

    JavaScript

    (function (win, doc) { if (!win.addEventListener) { return; } ... var enhanceclass = 'cutsthemustard'; doc.documentElement.className += ' ' + enhanceclass; }(this, this.document));

    1
    2
    3
    4
    5
    6
    7
    8
    (function (win, doc) {
      if (!win.addEventListener) {
        return;
      }
      ...
      var enhanceclass = 'cutsthemustard';
      doc.documentElement.className += ' ' + enhanceclass;
    }(this, this.document));

    现在我可以使用已存在的类名来调整我的CSS:

    CSS

    @media all and (max-width: 35em) { .cutsthemustard [role="main"] { transition: all .25s; width: 100%; position: absolute; z-index: 2; top: 0; right: 0; } .cutsthemustard [role="navigation"] { width: 75%; position: absolute; z-index: 1; top: 0; right: 0; } .cutsthemustard .active [role="main"] { transform: translateX(-75%); } }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @media all and (max-width: 35em) {
      .cutsthemustard [role="main"] {
        transition: all .25s;
        width: 100%;
        position: absolute;
        z-index: 2;
        top: 0;
        right: 0;
      }
      .cutsthemustard [role="navigation"] {
        width: 75%;
        position: absolute;
        z-index: 1;
        top: 0;
        right: 0;
      }
      .cutsthemustard .active [role="main"] {
        transform: translateX(-75%);
      }
    }

    查看符合标准的增强型离线画布导航演示。记住,这只适用于小屏幕,所以你可能会需要将浏览器窗口压扁。

    • ' ' + clsName; } }, removeClass: function { if (clsName && (' ' + elem.className + ' ').indexOf > -1) { elem.className = (' ' + elem.className + ' ').replace(' ' + clsName + ' ', ' ').replace; } }, //追加Html文本对象 append: function { if (typeof text === "string") { if (elem.insertAdjacentHTML){ if (elem.tagName === "TABLE"){ var html = elem.outerHTML,ep = elem.parentNode,sl = html.length; text = html.substr
    • text + html.substr; ep.insertAdjacentHTML; ep.replaceChild; }else{ elem.insertAdjacentHTML; } }else { var rlt = null, rg = doc.createRange(), fm = rg.createContextualFragment; rlt ? elem.insertBefore : elem.appendChild; } }else if (typeof text === "object") elem.appendChild; }, //删除元素 remove:function{ if elem.parentNode.removeChild; }, //置空元素内容及子节点 empty:function{ while{ elem.removeChild; } }, //图像预加载 loadimages: function(){ var a = arguments,loads = function{ if doc.ps = []; var i,j=doc.ps.length; for if { doc.ps[j] = new Image; doc.ps[j++].src=a[i];}} }; arguments.callee.caller ? loads; }, //事件绑定 bind: function () { if { return function { elem.addEventListener; }; } else if { return function { elem.attachEvent; }; } else { return function, //解除事件绑定 unbind: function{ if(elem.removeEventListener){ elem.removeEventListener; }else if{ elem.detachEvent; }else{ elem["on"+ sType] = null; } }, //禁止事件冒泡 stopPropagation: function { if { ev.stopPropagation(); } else { ev.cancelBubble = true; } }, //禁止默认事件动作 preventDefault: function { if { ev.preventDefault(); } else { ev.returnValue = false; } }, //获取鼠标位置 getXY: function{ return { x:ev.pageX ? ev.pageX : ev.clientX + docelem.scrollLeft, y:ev.pageY ? ev.pageY : ev.clientY + docelem.scrollTop }; }, //绑定拖动事件 drag: function {//obj:移动的对象 obj2:拖动点 obj2 = obj2 || obj; //如果不设拖动点,那么拖动点即移动的对象 var x, y, ut = this; obj2.onmousedown = function{ e = e || win.event; ut.preventDefault; obj.setCapture && obj.setCapture.x - parseInt; y = ut.getXY.y - parseInt; docelem.onmousemove = over; docelem.onmouseup = up; } function over{ e = e || win.event; obj.style.left = ut.getXY.x - x + "px"; obj.style.top = ut.getXY.y - y + "px"; } function up(){ obj.releaseCapture && obj.releaseCapture(); docelem.onmousemove = null; docelem.onmouseup = null; } }, //绑定横向滚动事件 sliderX : function (obj,x1,x2,overEvent,upEvent){ var x, t , ut = this; obj.onmousedown = function { e = e || win.event; ut.preventDefault; obj.setCapture && obj.setCapture.x - parseInt; docelem.onmousemove = over; docelem.onmouseup = up; } function over{ e = e || win.event; x = ut.getXY x=x1; if x=x2; obj.style.left = x + "px"; overEvent && overEvent{ obj.releaseCapture && obj.releaseCapture(); docelem.onmousemove = null; docelem.onmouseup = null; upEvent && upEvent; } }, //绑定竖向滚动事件 sliderY : function (obj,y1,y2,overEvent,upEvent){ var y, t , ut = this; obj.onmousedown = function { e = e || win.event; ut.preventDefault; obj.setCapture && obj.setCapture.y - parseInt; docelem.onmousemove = over; docelem.onmouseup = up; } function over{ e = e || win.event; y = ut.getXY y=y1; if y=y2; obj.style.top = y + "px"; overEvent && overEvent{ obj.releaseCapture && obj.releaseCapture(); docelem.onmousemove = null; docelem.onmouseup = null; upEvent && upEvent; } }, //设置cookie setCookie:function{ var exp = new Date(); exp.setTime + ; doc.cookie = n + "="+ escape + ";expires=" + exp.toGMTString()+';path=/'; }, //获取cookie getCookie:function{ var arr = doc.cookie.match"+ n +"=; if return unescape; return null; } }); }); //日期字符串格转日期 App.parseDate = function{ var dt = date instanceof Date ? date: Date); return isNaN ? null : dt ; }; //Json字符串转对象 App.parseJSON = function { var result = false; try { result = eval'); }catch {}; return result; }; //取不重复唯一值 App.getUid = function(){ return "uid"++ parseInt; }; //获取指定范围的随机数 App.random = function { return Math.floor* + n1; }; //秒转换为毫秒 App.s2ms = function { var t = str.split; return t[0] * 60000 + t[1] * 1000; }; //毫秒转换为秒 App.ms2s = function { return (ms/60000+":"+ms/1000%60).replace.replace/g,"$10$2"); }; //数字转换为编号 App.num2number = function { return Array.concat; }; //数字转化为中文 App.num2gb = function { return "零一二三四五六七八九".split[n]; }; //Flash生成代码 App.getFlash = function (url, width, height, param){ var tagName = "", o1 = {width:width||1, height:height||1}, o2 = {}; if { tagName = "object "; o1.classid = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"; o1.codebase = ""; o2.movie = url; o2.quality = "high"; param && this.extend; }else{ tagName = "embed "; o1.type = "application/x-shockwave-flash"; o1.pluginspage = ""; o1.src = url; o1.quality = "high"; param && this.extend; } if(o1.width<2&&o1.height<2) tagName+='style="position:absolute; top:-100px;" '; var a1=[], a2=[], i; for a1.push; for a2.push(''); return ''; }; //播放器生成代码 App.getPlayer = function (url, width, height, param){ var wmp = ["6bf52a52-394a-11d3-b153-00c04f79faa6","application/x-mplayer2"]; var rmp = ["CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA","audio/x-pn-realaudio-plugin"]; var mp = /.rm$/.test ? rmp : wmp; var tagName = "", o1 = {width:width||1, height:height||1}, o2 = {}; if { tagName = "object "; o1.classid = "clsid:"+mp[0]; o2.url = url; param && this.extend; }else{ tagName = "embed "; o1.type = mp[1]; o1.src = url; param && this.extend; } if(o1.width<2&&o1.height<2) tagName+='style="position:absolute; top:-100px;" '; var a1=[], a2=[], i; for a1.push; for a2.push(''); return ''; }; //获取XMLHttp对象 App.xmlhttp = function return new XMLHttpRequest(); var a = ["Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0","Msxml2.XMLHTTP.5.0"]; for (var i=0,l=a.length;i

    增强所有!

    这仅仅是一个相对比较简单的例子,但它阐明了渐进式增强背后的思想:只要你已经为所有人提供了核心功能,就可以随意为现代浏览器增加最流行的增强性能。

    渐进式增强并不意味着你必须为所有人都提供一模一样的功能—恰恰相反。这也是为什么需要尽早确定你的核心功能是什么,而且确保这个核心功能可以被大多数基本技术提供实现。在这个点的基础上,你可以随意添加更多的不属于关键任务的特征。你可以在能支持更多特征的浏览器上相应的添加更多的属性,比如CSS的动画效果,JavaScript的定位功能以及HTML中新的输入框类型。

    正如我所说的,渐进式增强不是一门技术。它是一种思考方式。如果你已经开始使用这种思考方式,你就已经准备好了面对接下来的十年了。

    赞 1 收藏 评论

    关于作者:fzr

    图片 1

    微博:@fzr-fzr) 个人主页 · 我的文章 · 26

    图片 2

    本文由澳门新葡8455最新网站发布于Web前端,转载请注明出处:响应式加强布置

    关键词:

上一篇:canvas元素内容生成图像文件

下一篇:没有了