messenger,下载好了说手机下载steam打不开不支持打不开啊,谁懂吧想想办法

&p&之前很长的一段时间,一直负责在做阿里云人工智能产品 &a href=&//link.zhihu.com/?target=https%3A//et.aliyun.com/index& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ET&/a& &/p&&p&为了一名前端工程师,参与了当中的一些工程工作,分享出来,希望对大家有所帮助。&/p&&p&&br&&/p&&p&前端工程师在人工智能的团队到底能做什么,能体现怎么的价值?对此,可以先下图的一个总结,然后再会逐条结合实际以及业界的发展情况做一些分析&/p&&figure&&img src=&https://pic3.zhimg.com/v2-8adb9ef80a467aed0ce5a62_b.png& data-caption=&& data-size=&normal& data-rawwidth=&1364& data-rawheight=&498& class=&origin_image zh-lightbox-thumb& width=&1364& data-original=&https://pic3.zhimg.com/v2-8adb9ef80a467aed0ce5a62_r.png&&&/figure&&p&&br&&/p&&p&从我们的实践看,要完成一个完整的人工智能项目,三种东西是不可或缺的:&b&算法,数据和工程&/b&。&/p&&p&而前端在这三个方向种,最容易参与进去,同时也最容易做出彩的地方就是在工程方面,我们把这块内容叫做大前端。&/p&&p&具体的大致可以分为五块内容:&b&人机交互,数据可视化,产品Web, 计算,模型训练和算法执行&/b&。&/p&&p&对于前三点偏重交互的领域,毋庸置疑用前端做起来驾轻就熟,&/p&&p&而后面偏重计算的领域,前端是否合适做,或者说前端该怎么去做是有可以探讨的。&/p&&p&&br&&/p&&p&一. 人机机互&/p&&p&这个应该前端这几年发力的重点,而且取得不错进展的地方。&/p&&p&特别是随着HTML5技术,特别是移动互联网的普及,浏览器对硬件的控制越来越好。&/p&&p&在AI的项目中,很多时候需要获取麦克风和摄像头的权限,好实现“听”,“说”, “看”的功能。&/p&&p&具体可以参考 &a href=&//link.zhihu.com/?target=https%3A//developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&MediaDevices.getUserMedia&/a& 的 H5 文档,里面对这块有详细的介绍。&/p&&p&对于图片的处理,之前网上已经不少的用 Canvas 例子,我就不做过多的介绍。&/p&&p&这里重点对语音处理的内容,这块由于需要很多专业方面的知识,之前处理前端处理起来还是挺痛苦的,不过现在 &a href=&//link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Web Audio API&/a& 很好的解决了这个问题。&/p&&p&它提供了在Web上控制音频的一个非常有效通用的系统,允许开发者来自选音频源,对音频添加特效,使音频可视化,添加空间效果 等等。&/p&&p&更有甚者,Chrome中已经自动集成了语音识别的基础 SDK: &a href=&//link.zhihu.com/?target=https%3A//developers.google.com/web/updates/2013/01/Voice-Driven-Web-Apps-Introduction-to-the-Web-Speech-API& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Web Speech API&/a&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-2e89ffc5b4abd_b.png& data-caption=&& data-size=&normal& data-rawwidth=&1746& data-rawheight=&412& class=&origin_image zh-lightbox-thumb& width=&1746& data-original=&https://pic2.zhimg.com/v2-2e89ffc5b4abd_r.png&&&/figure&&p&&br&&/p&&p&二. 数据可视化&/p&&p&数据可视化 可以是前几年特别火的一个方向,特别是大数据风起云涌的时代&/p&&p&而这些年明显的趋势就是人工智能,就是AI,在这里其实也有很多可视化的工作&/p&&p&比如我们在 ET 项目中就需要做很多声音的可视化内容&/p&&figure&&img src=&https://pic1.zhimg.com/v2-b9f37b52cd4c1d_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&701& data-rawheight=&127& class=&origin_image zh-lightbox-thumb& width=&701& data-original=&https://pic1.zhimg.com/v2-b9f37b52cd4c1d_r.jpg&&&/figure&&p&&br&&/p&&p&以及现在外面在做的一些人脸可视化的内容&/p&&figure&&img src=&https://pic1.zhimg.com/v2-926f6a7107e93cfd08a5c447d15b61b0_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&779& data-rawheight=&541& class=&origin_image zh-lightbox-thumb& width=&779& data-original=&https://pic1.zhimg.com/v2-926f6a7107e93cfd08a5c447d15b61b0_r.jpg&&&/figure&&p&地址:&a href=&//link.zhihu.com/?target=https%3A//predictiveworld.watchdogs.com/en/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PREDICTIVE_WORLD, the program that predicts your future/&/a&&/p&&p&&br&&/p&&p&三. 产品Web&/p&&p&任何人工智能的技术最终一定需要转化成实际的产品或者项目&/p&&p&这样的话,往往少不了Portal和控制台。&/p&&p&这些工作,前端的工作也是在所难免。&/p&&p&这是常规的工作,这里就不再过多描述了&/p&&p&&br&&/p&&p&&br&&/p&&p&四. 算法执行&/p&&p&算法执行顾名思义,其实就是执行算法逻辑,比如人脸识别,语音识别
…&/p&&p&前几年有些大家对前端的认知还停留在纯浏览器端,但随着 V8 引擎在2008 年发布, Node.js 在2009 年 发布,前端的领地就扩展到服务器端,桌面应用。&/p&&p&这些算法执行的原先都需要后端同学开发,现在也可以由前端同学才完成。&/p&&p&我们很多AI的项目,很多时候往往就是算法的同学提供给我们一些动态链接库或者C的代码,我们通过Nodejs驱动这些服务提供 http接口,浏览器通过ajax来调用这些接口。&/p&&p&更有甚者,现在PC性能提升,V8对JS执行的优化,特别WebGL 在各个浏览器端的普及&/p&&p&很多算法执行不一定并不一定需要在后端执行,浏览器也可以胜任。&/p&&p&比如:&/p&&p&&a href=&//link.zhihu.com/?target=https%3A//trackingjs.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Tranck.js&/a&:就是纯浏览器的图像算法库,通过javascript计算来执行算法逻辑&/p&&figure&&img src=&https://pic1.zhimg.com/v2-fe6fecc8d16e6d42cc40c70dbdb38888_b.png& data-caption=&& data-size=&normal& data-rawwidth=&1566& data-rawheight=&622& class=&origin_image zh-lightbox-thumb& width=&1566& data-original=&https://pic1.zhimg.com/v2-fe6fecc8d16e6d42cc40c70dbdb38888_r.png&&&/figure&&p&&br&&/p&&p&&a href=&//link.zhihu.com/?target=https%3A//github.com/Erkaman/regl-cnn& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&regl-cnn&/a&: 浏览器端的数字识别类库,与track.js 不同的是,它利用浏览器的WebGL 来操纵GPU,
实现了CNN&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-71e844aaca1e88ecd778a7_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&324& data-rawheight=&204& class=&content_image& width=&324&&&/figure&&p&&br&&/p&&p&五. 模型训练&/p&&p&虽然现在阶段也出现了像 ConvNetJS 这种在浏览器端做深度学习算法训练的工具,&/p&&p&但整体而言,前端在这块还是非常欠缺的,同时缺少非常成功的实践。&/p&&p&究其原因,还是因为跨了领域,特别是专业类库往往都不是javascript写的,造成更大的隔阂&/p&&p&但就像谷歌的TensorFlow机器学习框架底层大部分使用 C++实现,但选择了 Python 作为应用层的编程语言。&/p&&p&Javascript 在各个端,特别是web端的优势,也是一门非常优秀的应用开发语言。&/p&&p&可喜的是看到挺多同学在往这个方向走,我们拭目以待&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/convnetjs/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ConvNetJS&/a&:Deep Learning in your browser&/p&&p&&br&&/p&&p&写在最后:&/p&&p&如果大家对这块感兴趣,也希望来阿里巴巴一起做大数据和人工智能相关的工作,随时欢迎发简历给我:jifeng.。大家一起合作,做件有意义的事情&/p&
之前很长的一段时间,一直负责在做阿里云人工智能产品
为了一名前端工程师,参与了当中的一些工程工作,分享出来,希望对大家有所帮助。 前端工程师在人工智能的团队到底能做什么,能体现怎么的价值?对此,可以先下图的一个总结,然后再会逐条结合实际…
给杨老师补充下:&br&&br&事实上,之所以这些概念会给很多人造成困惑的原因在于,现代Application的抽象层级比较多,高度细分。所以,在这个议题里我们把Node.js 这个framework看作是应用层,libuv看做是IO调度层,kernel看做是实际的IO发生层。&br&&br&正如杨老师说的,Node.js底层使用的libuv封装了多个目标平台的io函数,并在Linux系统中使用epoll给上层应用模拟出了一套异步I/O,而epoll本身却是同步的。(反正阻塞非阻塞的都是同步IO)&br&所以这时候就可能会出现概念的模糊,事实上这里的第一个「异步」是Node.js相对于libuv而言,而第二个「同步」则是libuv相对于kernel而言的。而对于Node.js的用户而言,下层是被屏蔽且不需要关心的。&br&所以更明确的事实就是,Node.js里由于我们并不直接与kernel发生IO调用,因此你所能拥有的调用模式实际上取决于libuv所提供的实现。(浏览器亦然)&br&&br&&figure&&img src=&https://pic4.zhimg.com/b3af9039cf03ccf06a6f8e37340cac07_b.png& data-rawwidth=&614& data-rawheight=&327& class=&origin_image zh-lightbox-thumb& width=&614& data-original=&https://pic4.zhimg.com/b3af9039cf03ccf06a6f8e37340cac07_r.png&&&/figure&&br&而从实际的使用来看,libuv对Node.js一共就提供了上图中第一以及最后的(模拟的)两种IO模型。
给杨老师补充下: 事实上,之所以这些概念会给很多人造成困惑的原因在于,现代Application的抽象层级比较多,高度细分。所以,在这个议题里我们把Node.js 这个framework看作是应用层,libuv看做是IO调度层,kernel看做是实际的IO发生层。 正如杨老师说的,N…
题主的疑惑很正确,同步还是异步与是否阻塞确实没有必然关系,但纠正一下:&br&&ul&&li&阻塞与同步一般代表同一件事&br&&/li&&li&非阻塞和异步在很多情况下一般也等同&/li&&li&阻塞一般关注的进程的状态,进程停下等待数据返回&/li&&li&异步一般是一种通知机制&/li&&/ul&举个例子,nodejs 底层的 libuv 库,封装了 epoll,它是一个同步 IO,它在数据操作的时候是阻塞的,但 libuv 实现的却是一套异步机制。&br&&br&更详细的请参考链接&br&&a href=&https://www.zhihu.com/question/& class=&internal&&怎样理解阻塞非阻塞与同步异步的区别? - 网络编程&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//stackoverflow.com/questions/2625493/asynchronous-vs-non-blocking& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&asynchronous vs non-blocking&/a&&br&&br&但是,如果加上 js 这个 context,因为它是单线程的,所以你在写 js 的时候基本没有自己发挥的空间, js 只剩同步阻塞和异步非阻塞了。&br&&br&TL;DR&br&&ul&&li&确实应该区别阻塞和同步两个概念&/li&&li&js 里,不存在同步非阻塞和异步阻塞&/li&&li&不存在异步阻塞这种奇怪的概念&/li&&/ul&
题主的疑惑很正确,同步还是异步与是否阻塞确实没有必然关系,但纠正一下: 阻塞与同步一般代表同一件事 非阻塞和异步在很多情况下一般也等同阻塞一般关注的进程的状态,进程停下等待数据返回异步一般是一种通知机制举个例子,nodejs 底层的 libuv 库,封装…
&p&返回4xx还是返回200然后结果里写error,这个就好比编程语言里面,是用抛出异常表示错误,还是用返回errno来表示错误(实际上大部分的HTTP client库也是会在4xx/5xx状态码出现的时候抛出相应异常的)。现代的编程语言,除了C这样的比较老的标准的,C++这样的继承了很多C的习惯的导致很多人不习惯用异常的,Go这样的奇葩开倒车的,其他都是使用异常来表示错误,这样就保证你不会轻易漏掉任何一个错误。&/p&&p&你用200表示业务错误,那你难道就不处理4xx/5xx的错误了吗……这不就是让调用方把异常处理写两遍吗。当然某些前端肯定会说,我从来不写onerror,或者只用全局的onerror,那是你懒,不是你让后端纵容你的懒惰的理由。&/p&&br&&p&返回状态码一个非常重要的应用是access日志的监控,像ELK这样的工具可以自动分析nginx access log这样整齐的日志,解析出其中的字段,这样就可以在某个接口频繁出现4xx/5xx报错的时候自动发送告警。如果你全返回200,那就只有最终用户才知道你接口挂了。&/p&&br&&p&这其实是个比较严肃的问题,每个人开发的时候都有自己的喜好,尤其是某些人做前后端全栈,可能就喜欢让后端的设计配合着我前端代码的风格来,但是对于比较严谨的开发来说是不应该这样的。它跟你写代码的风格不一样,你说你写代码就喜欢变量名不用英文用汉语拼音,那最多也就是跟你一起开发的同事骂你一句SB而已;而HTTP状态码这是个对外的接口,尤其对于RESTful API来说,你是没有办法假定将来只有某个组件调用它,而专门为了那个组件实现起来方便(比如为了javascript不写onerror)而改返回码含义的,对于一个比较大的工程来说,可能会用到很多第三方组件,这些组件只会按照业界通行的标准来设计,对于HTTP来说大部分都会默认返回200就是成功,这样你就要费更大的功夫专门为了你的私有标准来开发整套的运维工具。所以&b&永远不要跟业界通行的方法背着干,这不是个个人偏好的问题,是关系到项目生死的大事&/b&。&/p&&br&&p&通行的HTTP返回失败的方法是返回相应的HTTP状态码,然后设置Content-Type: application/json,返回一个JSON串,其中包括错误信息。调用方的错误处理逻辑是:首先判断HTTP返回码,如果为4xx/5xx,则检查Content-Type并尝试使用JSON解析HTTP正文,如果JSON解析失败,按照未知异常处理(可能是WebServer或者中间件返回的错误),直接将返回的消息体字符串写进日志。&/p&
返回4xx还是返回200然后结果里写error,这个就好比编程语言里面,是用抛出异常表示错误,还是用返回errno来表示错误(实际上大部分的HTTP client库也是会在4xx/5xx状态码出现的时候抛出相应异常的)。现代的编程语言,除了C这样的比较老的标准的,C++这样的…
&p&先用技术语言解释一下楼上几位的答案:&/p&&p&1. JavaScript 是图灵完备的;&/p&&p&2. 图灵完备的语言&i&理论上&/i&可以解决目前所有的计算机编程问题;&/p&&p&3. JavaScript 简单灵活,&i&应该会是&/i&解决大部分问题的优选方案。&/p&&p&所以,&b&理论上,JavaScript 可以成为人工智能的开发语言。&/b&&/p&&p&著名程序员 Jeff Atwood 在2007年发布了著名的 Atwood's Law: &/p&&blockquote&Any application that &i&can&/i& be written in JavaScript, &i&will&/i& eventually be written in JavaScript. &br&“一切&i&可以&/i&用 JavaScript 编写的程序,最终&i&都会&/i&使用 JavaScript 编写。”&/blockquote&&p&很快,2008 年 V8 引擎发布,2009 年 Node.js 发布,拉开了 JavaScript 攻城略地的序幕,服务端、数据库、OS、无线、桌面应用,甚至嵌入式设备,都相继出现了 JavaScript 的身影。&/p&&p&同时,ECMAScript 标准的不断完善和严谨,让这门语言在更多领域成为生产方案成为可能。&/p&&p&这当然也包括人工智能领域。很多人已经开始尝试使用 JavaScript 解决 AI 问题,比如:&/p&&ul&&li&ConvNetJS:&a href=&//link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/convnetjs/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Deep Learning in your browser&/a&&/li&&li&Mind.html: &a href=&//link.zhihu.com/?target=http%3A//mind.sourceforge.net/userman.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&User Manual of Mind.html Tutorial Artificial Intelligence (AI)&/a&&/li&&/ul&&p&但是,&i&可以&/i&与&i&适合&/i&之间,存在着很大的距离。 与传统的语言相比,JavaScript 在人工智能领域还有很大的&b&弱势&/b&:&/p&&p&&b&1. 专业库缺失&/b&&/p&&p&JavaScript 真正脱离浏览器进入其他领域,也就近七八年的时间。而人工智能领域需要的大量专业基础库,如基础算法实现、数学计算、图像处理等,都已经发展了几十年,而像 Lisp 等内置部分 AI 计算能力的语言,及 MATLAB 等专业软件,也已积累了大量的库、扩展、例程等生态,这些都是 JavaScript 社区短期内很难补齐的。&/p&&p&&b&2. 语言本身的短板&/b&&/p&&p&人工智能对计算的需求,表现在运算量大、对内存及数据的精确控制、对 CPU/GPU 的便捷操作、分布式处理等,这些场景下,C/C++ 有更多的优势和经验。&/p&&p&JavaScript 当然理论上有办法实现,但也要依赖 Node.js 引擎及其下层的处理,在生产环境中并无必要多此一举。&/p&&p&&b&3. 领域的惯性&/b&&/p&&p&人工智能学科的学习周期长门槛高,领域相对封闭。科研机构和学校长期使用 Lisp、ProLog 等语言用于 AI 研究和应用,已经积累了强大的惯性。JavaScript 这门“新语言”很难直接切入如此之长的行业链条。&/p&&p&JavaScript 当然也有其&b&优势&/b&:&/p&&p&&b&1. 语言灵活,社区庞大&/b&&/p&&p&TensorFlow 底层大部分使用 C++实现,但选择了 Python 作为应用层的编程语言。在这一层面上,JavaScript 具备和 Python 同样的竞争力。加上 JavaScript 的社区极为繁荣,相信在社区、市场、成本、效率等综合因素影响下,JavaScript 可以在应用层面有更多的机会。( TensorFlow 的非官方 JavaScript Wrapper 确实早已出现,并持续升温)&/p&&p&&b&2. Web! Web! Web!&/b&&/p&&p&互联网革命的核心,在于“端”的力量。&/p&&p&如同当年网格计算、BT下载的理念对行业产生的巨大影响,在物联网时代,“端”的数量呈指数增加,更是为分散式计算提供了绝佳场景。用户交互行为、声音图像、地理位置、运动健身等产生的数据,完全有可能在计算能力越来越强的“端”中实现标注、预处理、计算。而由于在跨平台(浏览器、客户端、服务端、设备…)上的优势,JavaScript 将是提供端计算一致化方案的最佳语言。&/p&&p&同时,用户界面交互也是 AI 产业化的重要环节,JavaScript 在界面上也将迎来更广阔的空间。&/p&&p&&b&JavaScript 发端于 Web,她带着 Web 的基因,也必将以 Web 的理想在新时代更远的前行。&/b&&/p&&p&------------------&/p&&p&以上是我作为物联网从业的前端工程师的一点粗浅思考,关于物联网与前端工程师,欢迎关注我的知乎Live:《&b&物联网:前端工程师的新蓝海&/b&》 &a href=&https://www.zhihu.com/lives/809664& class=&internal&&知乎 Live - 全新的实时问答&/a&&/p&
先用技术语言解释一下楼上几位的答案:1. JavaScript 是图灵完备的;2. 图灵完备的语言理论上可以解决目前所有的计算机编程问题;3. JavaScript 简单灵活,应该会是解决大部分问题的优选方案。所以,理论上,JavaScript 可以成为人工智能的开发语言。著名程…
&p&在 &a href=&//link.zhihu.com/?target=http%3A//conf.reactjs.org/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&conf.reactjs.org/&/span&&span class=&invisible&&&/span&&/a& 上,Lin Clark 通过漫画为我们介绍 Fiber,结合她的介绍,我谈谈我的理解:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-d7accf34d3d3dc858e284ead_b.png& data-rawwidth=&1920& data-rawheight=&1200& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&https://pic2.zhimg.com/v2-d7accf34d3d3dc858e284ead_r.png&&&/figure&&p&Fiber 可以提升复杂React 应用的可响应性和性能。Fiber 即是React新的调度算法(reconciliation algorithm)&/p&&figure&&img src=&https://pic1.zhimg.com/v2-e5fbd78b119a1e8bf4e0_b.png& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&https://pic1.zhimg.com/v2-e5fbd78b119a1e8bf4e0_r.png&&&/figure&&p&react 即 reconsiler(调度者),react-dom则是 renderer。调度者一直都是又 React 本身决定,而 renderer 则可以由社区控制和贡献。&/p&&p&那新的调度算法是如何优化可响应性和性能的呢 ?&/p&&figure&&img src=&https://pic3.zhimg.com/v2-f1b58ac0a8cf28c4f51a_b.png& data-rawwidth=&1440& data-rawheight=&900& class=&origin_image zh-lightbox-thumb& width=&1440& data-original=&https://pic3.zhimg.com/v2-f1b58ac0a8cf28c4f51a_r.png&&&/figure&&p&每次有 state 的变化 React 重新计算,如果计算量过大,浏览器主线程来不及做其他的事情,比如 rerender 或者 layout,那例如动画就会出现卡顿现象。&/p&&figure&&img src=&https://pic2.zhimg.com/v2-d05db8d8c9aa3c306c6d9_b.png& data-rawwidth=&1440& data-rawheight=&900& class=&origin_image zh-lightbox-thumb& width=&1440& data-original=&https://pic2.zhimg.com/v2-d05db8d8c9aa3c306c6d9_r.png&&&/figure&&p&React 制定了一种名为 Fiber 的数据结构,加上新的算法,使得大量的计算可以被拆解,异步化,浏览器主线程得以释放,保证了渲染的帧率。从而提高响应性。&/p&&p&React 将更新分为了两个时期:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-86baa2e125f73b2ae7fcd482eff4f11e_b.png& data-rawwidth=&1440& data-rawheight=&900& class=&origin_image zh-lightbox-thumb& width=&1440& data-original=&https://pic3.zhimg.com/v2-86baa2e125f73b2ae7fcd482eff4f11e_r.png&&&/figure&&h2&render/reconciliation&/h2&&figure&&img src=&https://pic1.zhimg.com/v2-f24c387d37d7ee4a43eae4_b.png& data-rawwidth=&1440& data-rawheight=&900& class=&origin_image zh-lightbox-thumb& width=&1440& data-original=&https://pic1.zhimg.com/v2-f24c387d37d7ee4a43eae4_r.png&&&/figure&&p&可打断,React 在 workingProgressTree 上复用 current 上的 Fiber 数据结构来一步地(通过requestIdleCallback)来构建新的 tree,标记处需要更新的节点,放入队列中。&/p&&h2&commit&/h2&&figure&&img src=&https://pic2.zhimg.com/v2-aea949fe149a9f_b.png& data-rawwidth=&1440& data-rawheight=&900& class=&origin_image zh-lightbox-thumb& width=&1440& data-original=&https://pic2.zhimg.com/v2-aea949fe149a9f_r.png&&&/figure&&p&不可打断。在第二阶段,React 将其所有的变更一次性更新到DOM上。&/p&&p&除此之外,还有更多的优化细节,可以参看 Lin Clark 的&a href=&//link.zhihu.com/?target=http%3A//conf.reactjs.org/speakers/lin& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&演讲视频&/a&。&/p&&br&&h2&&b&广告时间&/b&&/h2&&p&欢迎关注 &a href=&https://zhuanlan.zhihu.com/FrontendMagazine& class=&internal&&前端外刊评论 - 知乎专栏&/a&,外刊君将会代码 React Conf 2017 的全部解读。也可以微信、微博搜索 FrontendMagazine 关注,期待后续。&/p&
上,Lin Clark 通过漫画为我们介绍 Fiber,结合她的介绍,我谈谈我的理解:Fiber 可以提升复杂React 应用的可响应性和性能。Fiber 即是React新的调度算法(reconciliation algorithm)react 即 reconsiler(调度者),react-dom则…
之前扒了下代码,应该用的这个库:&a href=&//link.zhihu.com/?target=https%3A//github.com/cburgmer/rasterizeHTML.js& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&github.com/cburgmer/ras&/span&&span class=&invisible&&terizeHTML.js&/span&&span class=&ellipsis&&&/span&&/a&
之前扒了下代码,应该用的这个库:
更新:根据评论反馈,这篇Checklist可能放在这个题目下回答并不太合适,这个回答其实并不针对本题人物。那天有人Po这个,最近看到很多互撕就回答了。基本上算是General Purpose的前端选择建议,也就是说不是特别确定选什么的时候React各方面都不吃亏。&br&&br&而结合实际情况,对于在TB的这个例子里,民工叔选了两个正确的方向:&br&1. Web Vue兼容已有的Mobile:这个显而易见,技术栈越分裂痛点越多。&br&2. 对于重数据模型的改造使用Rx:已有重型数据层,而Redux需要另外一个Store,侵入性强,成本高风险大,Rx对数据源进行响应式订阅,可以平缓地将本来已经碎片化的多处状态重新整理并统一起来。&br&&br&另外比较有意思的点是争执不下的时候选了第三个框架ng2……一面觉得可以把React模式拿回ng2里写,一面觉得反正ng2有Rx。这种结果其实对团队非常不好,大家都选一个能实现自己想法的土壤,然后分别实现自己的想法,像占领高地一样开发。这是非常麻烦的状况,像原文说的:&br&&blockquote&三民主义和共产主义都能救中国,但两个不能一起上。&/blockquote&&br&--&br&&br&以上讨论完对于维护这个现有系统的选择,我们也可以考虑如果现在新开一个TB这种应用开发的项目理想上适合什么。对于TB这种复杂交互,状态和推送特别多的应用而言,更像一个完整的桌面应用,这也是未来Web应用的发展方向。民工叔也提到,有个非常明显的痛点就是:&br&&blockquote&另外,数据模型之间的监听关系也存在缺失,由于Teambition产品交互的特殊性,很多视图要共享一些业务数据,而且是全业务存在WebSocket推送,不把监听关系全部写对的后果是,可能你改了某个地方的数据,原先应当同步的十多个集合里面,漏通知了某些,那些对应的视图就不一致了。&/blockquote&我现在也在做一个复杂的SPA,某些部分和TB应用有很多类似之处。感受上其实首要痛点并不是现在主流框架所着眼的前端数据模型问题,对于这种问题,比较老道的前端,其实不管用单向数据流还是MVVM都能很好的解决了。&br&而这种应用面临的问题就是数据模型之间不同步,需要响应式的绑定,让数据来源统一。前端统一起来,比如通过Observable来分发是可以做到的。最麻烦的地方在于后端,比如你要在Store保存一个评论列表,点击Save将后端列表更新,这时候为了不刷新页面,前端也要根据后端状态码分别处理添加成功和失败的处理逻辑。同时,因为多用户互动而要引入的WebSocket push就让这种复杂度进一步提升。&br&于是我们发现,在构建SPA应用时特别容易前后端各写一份业务逻辑,这样不仅开发繁琐,容易不一致。而以后修改时,纯前端或后端业务可以靠IDE找到,而散落在两边的业务特别容易遗漏。而诸如Relay,Falcor和Om.next这些框架的处理方式应对这种情况要容易很多:前端的组件仅声明自己所依赖的后端数据,当后端数据更新时,根据是否为用户自己的行为更新或是其他角色更新,分别通过缓存算法或服务端推送的方式来自动更新数据加载。这样前后端的职责就变得明确了:前端仅作为向导角色决定用户看什么,改变什么,而业务处理则尽量收回到后端处理。这样前端的逻辑就可以抽象到第三方库中:组件被通知自己被更新就拿着自己的查询语句,去服务端自己更新数据。&br&这种“前端CRUD”的方式其实很大程度地回归了旧式网站的简单性,同时保证了还是SPA的体验。这时候回想下写Rails应用,或者甚至写Php应用的感觉吧:后端渲染的时代写网站是那么容易,因为每次用户都会刷新页面,这样不用算哪个组件更新了状态,总能获得最近状态。&br&这种模式还有个好处是,因为前端自己有控制查询内容多少的权利,后端无意义的CRUD controller几乎就全消失了,并且这些Controller以前经常要满足不同客户端的需求,而这种代码并不在应该在后端领域内解决。&br&当然这些库现在并不完美,但是在前端应用一直飙升的现在,我们可以通过它们看到前端未来的发展方向。&br&&br&另外提一个关于View测试的点,原文:&br&&blockquote&“我认同在数据和业务逻辑层使用FP或者FRP以更好地抽象,并且覆盖全量测试,但在贴近视图这里,还是坚持自己的看法:在MDV(数据驱动视图)的情况下,没有必要对业务视图组件做测试,只需保证数据正确即可。在这一点上,我跟很多团队成员是有分歧的。”&/blockquote&这时候其实双方都有理。但我也经常觉得大部分时候得没必要对视图组件做测试。&br&不过要做测试的话,React的成本会非常低,这也和React生态圈和其使用者更关注测试有关。假如觉得Enzyme的成本还是高的话,其实有个更好的东西叫Snapshot testing:&br&&a href=&//link.zhihu.com/?target=https%3A//facebook.github.io/jest/blog//jest-14.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Jest 14.0: React Tree Snapshot Testing · Jest&/a&&br&总之就是扫描视图组件生成一个Enzyme快照,然后每当有人改了其他东西Break掉这个组件渲染结果时都像Git一样要你提交,意思是问这个组件是你有意Break的嘛?如果是就commit,不是就看自己哪改错了,这种测试成本极低,但是能捕获非常多的视图API变更,特别在Redux这种父子组件数据接口有强依赖关系的状况下。&br&&br&---&br&更新:&br&公说公有理,婆说婆有理,前端圈子混战的时候都会说自己是最好的,这个回答列举React的优点,很多都被反复列举过了,其实并不是特别有建设性,也比较不负责任。为了让这个回答有些帮助,先讨论下React的一些潜在设计缺陷,这些点其实很少被提到,但是它们是这个框架重要的设计因素,也会影响到使用者的代码实现。但请注意,列举一些缺点并不代表它比别的框架差。&br&&b&1. React不方便作为事件源:&/b&&br&众所周知,React的核心 目标是作为一个View库,它本身专注于视图,接受数据结构作为属性,被动地渲染数据结构。这作为View库并无问题。而React整体是建立在它Virtual DOM之上的,和真实DOM交互很不自然。这时候你仔细思考就可以发现:DOM除了用来渲染,其实还有另外一个职责——捕获事件。也就是说DOM是事件的来源。前端展现绝大部分时候只受用户事件和后端状态这两个因素影响,也就是说前端开发的本质就是把网络请求和DOM事件组合到一起Map成View就完事了。&br&而React作为一个渲染库,很难将其作为捕获DOM事件的数据源,它接受这种统一来源的数据,可以很好地完成渲染任务,而对于事件,则没有一个简单地办法捕获所有React组件的事件,而做到这个最简单的办法就是选择器,而React的设计很可能以后都不会加入选择器,这和JVM很多地方很像,很可靠,但是总少点啥好用的(泛型,一等函数,一等模块这些基本功能的加入都要进行大规模更新……)。&br&而诸如Vue Cycle这些库则没有这种限制,所以有比较好用的Vue-rx。对于React,你只能像Mobx那样建立个Observable的store,这解决的问题和Redux其实类似,并不能很好地将React作为事件源。这个问题导致的后果就是,React在解决大量有事件的交互的场景时,你并不能简单地Observe Virtual DOM的事件来像数据一样统一处理,结果是非常麻烦的。&br&&b&2. Redux没有解决异步问题&/b&&br&反对Redux的声音很多,我觉得很多理由比较见仁见智。我想说的点是Redux没有解决的事,也就是说,用了React / Redux,前端开发也并不能高枕无忧。&br&React解决了渲染问题,你在React组件大部分时候都在考虑如何渲染,不像MVVM,你把数据模型问题全都拿到外面去解决,至于如何解决,React干脆就没管。通过把复杂度挤出去,这样你就可以完全做好渲染工作了。&br&于是Flux / Redux就营运而生,它用来解决被React抛出来的烂摊子。于是我们看到这个基于事件分发的同步状态Store。Redux的一个核心设计在于同步Reduce所有逻辑,你的异步Action都在外面排好队再发进来,这样优点显而易见:既容易测试,又不用处理复杂情况,你就可以专心处理业务逻辑了。但是细心的朋友又发现了,Redux又把异步的烂摊子丢出去了。Redux-thunk这种只是允许你异步Dispatch,而异步本身还是要你自己来处理。现在也有些Saga或者Observable相关的库来解决这些问题,但也并不是很方便——为了保证Redux本身的简洁性又引入一堆复杂的补丁来支持它。&br&说到这里大家就能发现,这种分治法虽然有效,但是还是有恼人的问题没处理完,特别是React本身封装了DOM,既没有解决这个问题域内中事件问题,也没有把这个问题域内的所有处理权,像对数据一样很好地暴露出来,让外部可以更好地解决。&br&&br&---&br&&br&原答案:&br&前端这几年迅猛发展,复杂度飙升,大家都在比谁管理数据更好更厉害。然后就忘了真正的前端和用户接触,有非常多的细节要考虑。我们现在看见太多的公司技术人员仅仅把前端框架的选型关系到个人爱好上,忘了在前端领域客观存在的诸多问题——而前端框架是应该用来解决这些问题的,我把其中一些列出来,谈谈为什么应该绝大部分情况用React,如果选型人员Check过这个列表,再选其他框架也无可厚非了:&br&&b&0. 说在前面:&/b&&br&
为了防止很多人反过来说React复杂之类的话(其实不算复杂,你要坚持全stateless,细粒度多复用的好习惯,最终代码量比MVVM少多了),先说明以下Checklist只基于一个前提,就是所做得前端应用至少要中等复杂,网站应该随处可见Ajax call和动态交互。如果后段渲染,前端比较简单,强烈推荐接着用jQuery——jQuery比你们想象的好用,特别是结合Rx,比Rx + React,Rx + Vue不知高到哪去了,因为讽刺的是,现在的主流框架没有一个能方便批量捕获事件作为数据源的(像Cycle那样),这也从一个方面说明了,这么多年前端主流撕来撕去都是那点破玩意,表面层出不穷各种fatigue,如果你仔细研究,实质上全都是同质的。&br&
换句话说,就现在而言,介于解jQuery和React问题域之间复杂度的框架,都纯属添乱。&br&&b&1. 数据管理:&/b&&br&
这几乎成为大家仅剩的关注点了。这些年前端大火,交互复杂度飙升,所有人都在关注怎么管理数据,相信大家现在对各种单项数据流框架了若指掌,就不多聊了。不管React还是Vue,Rx或者Redux,其实都是很好的选择(换句话说其实没那么大区别,硬要说的话Rx偏复杂事件,Redux偏好测试和维护)。&br&
值得一提的是单向绑定总是优于双向绑定,你可以给单向绑定列出很多客观的优点,而完全不能给双向列出一个非主观优点。如果非要用双绑,请参考列表第0条。&br&&b&2. 生态&/b&&br&这是很多人次要考虑的事情,毕竟是个轮子都要自己写延误了工期被老板一顿干不是好受的。Vue和React看起来都有很好的生态,虽然有差别,但也没差过一个数量级。&br&
然而我来告诉你,事实上并不是那么回事。大部分复制粘贴的组件库,大家都有,最多是好坏而已,而那些组件库,自己花不到半天功夫也都能抡个大概。说到生态,其实你更应该关注你短时间解决不了的事情。这也是我自己会用om.next,cycle等等这些类库,但是我绝对不会再有点规模的生产环境推荐的原因。下面列举几个,每一个想想自己要做多久,或者还是直接放弃:&br&
I. React DnD,简单处理任何拖动,拖动瞬间进行一个Canvas快照并且保持数据引用,这样可以像Redux一样简单控制逻辑,想想自己能做多快多好用。&br&
II. Redux Form, Redux的表单处理,想想没有这个库的时候React写个表单多操蛋,然后比比有了它之后抡表单多快,并且轻松和任何其他页面元素交互,想想其他库处理表单和全局状态交互的逻辑要多坑爹。&br&
III. Fixed Data Table,顾名思义,就是个Fixed表格,有非常多的性能优化,光做个Bug的Fix表头要多久。&br&
IV. Draft.js,超级富文本编辑框架,用这个可以轻易完成任何富文本编辑框,优点是完全不Opinionated,重写个这个可能你就要直接放弃了吧。&br&
VI. React Native。这个就不解释了,哈哈哈。不过Vue有个Weex,哪个好用自己掂量。&br&
VII. Relay & GraphQL。天天逼逼前端框架,多新多潮的技术,结果当你明白过来的时候,会发现这些框架都是完全类似的。而这两个玩意这个才真正解决了的前端的重大问题,不信可以试着想想如下几个重要问题:&br&
(1). 你知道怎么Update一个后端资源,仅仅声明这项改变可能改变后端的某几项资源的名字,然后任何前端逻辑代码都不写,魔法般精确自动更新整个应用所有依赖这个后端资源吗,并且仅仅请求变更过的资源,而不是相关的所有内容?&br&
(3). 你知道怎么用一个请求直接Load出一个用户的所有Repository的所有关注者嘛?常规请求你要先请求用户资源,这个请求返回之后,渲染后发第二个请求Repository的请求,有时候你还要再等返回之后再请求返回者列表。你看,3个请求甚至都不是并发的,而是串行的。加载速度之慢可想而知,而SPA一个页面甚至经常要有4,5次请求才能完成的情况。&br&
(2). 你知道父子组件之间不互相暴露接口就能合作,这样修改的时候就再也不会互相Break PropType了吗?&br&
不仅是Virtual DOM,Facebook在数据层上给我们展现了Diff算法和组件化设计出神入化的应用。&br&&b&3. JSX&/b&&br&
这又是React的一个能提出很多客观优点,而反对则只能提主观的点……偏偏还经常被外行吐槽。&br&
I. 静态编译,不至于跑到模板才挂,还容易补全。最逗逼的是我在用的某个TypeScript + 字符串模板的,并且还不少,静态检查全过,html挂了。不知道说啥好。&br&
II. JSX是JavaScript语法糖,好处是你可以像任何JavaScript对象一样操作和传递它。&br&
III. Enzyme可以直接用JSX字面量测试。&br&
IV. JSX是JavaScript对象,这意味着可以被Uglify压缩。ng,Vue等等字符串模板在大项目会非常占体积,最终导致你被迫进入很多工具链的研究(搞这些东西,太深入真的很恶心)。&br&
V. 加了TypeScript就更叼了。&br&&b&4. Virtual DOM&/b&&br&
一个字就是快,更关键的这是你进行一系列优化的基础:&br&
I. 想代码跑的快?你随时可以不改变代码结构,仅仅无脑把数据结构api换成Immutable来完成优化,然后下班回家。换别的框架你就要绞尽脑汁了,最后再优化也都是凑合。&br&
II. 想代码加载快,还想SEO,还想无缝变SPA?直接服务端渲染。值得的是React体积绝大部分都是Virtual DOM,React本身代码打包只有14K。&br&
III. 不仅要跑得快下得快,还要测试快。这是很多人都不注意的一点,当你花钱费劲用Phantom用Selenium加上Cucumber写出来的测试一跑半天还整天挂的时候,Virtual DOM在node上够跑无数次了,而且还可以是全并发的,也可以足够的E2E,覆盖你的业务。测试并行能力也是大项目重要指标,但是这种问题发生的时候基本已经无法挽回。我们现在跑前端测试15分钟,后端一上午。还想TDD?先抽根烟吧。真正的TDD体验是你修改代码的瞬间,就应该得到反馈。&br&
IV. 因为Virtual DOM就是你返回JavaScript对象React来渲染,所以配合Stateless,大部分时候可以做到引用透明,把函数式那套引进来,代码瞬间砍掉一大半,号称简单的MVVM库大部分代码都是我代码的好几倍。&br&&b&5. 工具链&/b&&br&
React工具链非常成熟。天天跟同事逼逼产品,UX这些见仁见智的,把技术抛在脑后,不如先把家伙磨亮点。开发体验好意味着高效率和好心情,这样跟PM撕逼直接说做不了的几率大大降低,软件质量大大提升。&br&
I. Hot reload。不刷页面直接写完网站。React的Hot Reload比其他主流框架都好得多(其实比cljs差好多,React一下不刷页面写完应用不太现实)。&br&
II. React & Redux devtools。Debug驱动开发快,还是TDD快?都不快,随时盯着Redux插件的状态调试,OK了再让这个插件自动帮你生成测试你直接粘贴走是最快的。&br&
III. 一切皆JavaScript。Webpack对React支持最好,其他的你自己要Spike好久,甚至可能自己写loader。分模块打包,懒加载直接可以和React Router按路由集成。对React生态来说,什么难需求都是白送的。&br&
IV. 别忘了你毕竟是前端,切图才是你的老本行。CSS module和组件直接集成,这个改进很可能远比不同框架间数据管理方便程度的差异更大。&br&&b&6. 其他&/b&&br& 这里说点稍微主观的。因为大家写代码都是团队在维护。Redux非常适合团队维护,觉得Redux可以试一下Ducks module,其实没那么麻烦,写到中期,统计下代码,代码还很可能更少。&br&对于一般的项目而言,大部分人实现需求的方式五花八门,导致互相看代码,维护代码特别烦。Redux比较单调,同时也比较可靠,这样所有人就能很轻易合作了。&br&&br&随便列举下就总结了这么多,仔细想想其实还有很多要补充的,现在先写这么多。有想要加进来的也可以告诉我一声。有反对意见我下次上线也会试着回复。&br&&br&反正总结一下就是:&br&你在选型的时候可能并不知道之后需要优化渲染速度/请求速度/加载时间,或者要加一个豪华富文本编辑器,再或者发现测试超难写,再或者还要买SEO服务等等。这时候代码已经写出来了,很多事情就只能继续忍受了。最烦的是,当你Roll off的时候,其他人还得继续接手。&br&&b&经验来说,很多需求是一开始看不到的。而当你选择React之后,诸如性能优化,分包压缩,工具链改进,写一些非常有挑战的代码这些需求可能就不复存在,而诸如服务端渲染,热加载,懒加载这些轻而易举,有时候你都感觉不到这时候它已经帮了你大忙(以上都是从React切换走之后血的教训)。&/b&&br&既然对于数据的处理非常见仁见智,难分高下,这时候其他因素反而变得重要而显而易见了。而当你给同事用上超快超好用的工具链时,他们会感谢你的。&br&&br&-----&br&&br&更新:&br&1. 关于Virtual DOM速度。前端是一个特殊领域,其中一个特殊之处是你对性能要求的标准仅仅是用户感觉不到卡顿。而Virtual DOM很大程度依赖Immutable数据结构,所以:&br&
I. Virtual DOM速度简单case的benchmark是没有参考意义的,因为谁都知道mutable更快,这是一个边际成本问题。重要的是应用扩大之后有没有卡顿,从而导致你要优化的可能性。&br&
II. Virtual DOM的速度之间的差异并不是数量级的差异,因此参考上一条,能Scale不卡就可以了。&br&2. 关于Redux。很多人对Redux印象非常不好,认为太繁琐,我在这里提一个需要写很多代码才能发现的点。Redux的Reducer是闭合的递归结构,这样当你的一块业务逻辑膨胀之后非常容易拆分,你只需要交给子Reducer处理,而不需要结构上的重构(毕竟你不是在写Java,JavaScript重构就是蛋疼。TypeScript帮助也有限,最近用Scala深有体会,Tooling很重要)。&br&这能保证你项目规模成长之后很少需要重构,这是大部分框架View和Model绑定的后期痛点。Facebook的库很多都能体现这一思想:组件结构是要递归且闭合的,从React的组件到高阶组件嵌套,再到Relay的fragment query,包括Reducer,代码结构都是引导你写出来一个树状求不动点的flow模型,这样总能保证表现力,而后期加功能不用再对代码结构妥协(Cycle是个更好的不动点模型)。这可能和React作者是Ocaml大神有关……(这段不理解也很难直观解释,多写代码多啃SICP把)。&br&3. 关于Relay。这个框架陡峭复杂是真的。但是它很像原版的Flux,Facebook的很多框架都是内部拿出来的,所以Api都没经过太多打磨,丢给社区发挥。Facebook并没有在现在把这个框架大幅推广,仅仅是因为这个框架是面向未来的。如果你大量地写复杂前后端,你就发现许多业务在前后端被不断的重复,导致大量浪费资源,并且某些业务不统,一要修改就同时前后端代码和测试,极难维护,并且还有大量Back end for front end的controller,这是所有复杂SPA的极大痛点。Relay对后端有要求,但是实现可以砍掉所有垃圾Controller,前端只作为Director控制流程,后端仅实现访问模型和权限管理。同时,多客户端可以轻易公用作后端接口(比如React Native)。&br&-----
更新:根据评论反馈,这篇Checklist可能放在这个题目下回答并不太合适,这个回答其实并不针对本题人物。那天有人Po这个,最近看到很多互撕就回答了。基本上算是General Purpose的前端选择建议,也就是说不是特别确定选什么的时候React各方面都不吃亏。 而结…
&figure&&img src=&https://pic2.zhimg.com/v2-5e1939bbf2e70f70fd7ff13c3a076809_b.jpg& data-rawwidth=&450& data-rawheight=&450& class=&origin_image zh-lightbox-thumb& width=&450& data-original=&https://pic2.zhimg.com/v2-5e1939bbf2e70f70fd7ff13c3a076809_r.jpg&&&/figure&&p&H.264被设定为取代VP8成为WebRTC服务的视频编解码器。&/p&&figure&&img src=&http://pic2.zhimg.com/v2-5e1939bbf2e70f70fd7ff13c3a076809_b.png& data-rawwidth=&450& data-rawheight=&450& class=&origin_image zh-lightbox-thumb& width=&450& data-original=&http://pic2.zhimg.com/v2-5e1939bbf2e70f70fd7ff13c3a076809_r.png&&&/figure&&p&微软上周在他们的Edge开发博客上宣布, Edge的ORTC开始支持H.264/AVC。&/p&&p&&b& ·
&/b&是的,它是ORTC而不是WebRTC&/p&&p&&b& ·
&/b&是的,它仅通过运行时标志就可以开启&/p&&p&&b& ·
&/b&是的,它只在Edge浏览器可用,IE浏览器不行&/p&&p&但话又说回来,这是目前唯一能够在Firefox、Chrome和Edge之间跨浏览器进行视频通话的方法。VP8和VP9至多能让你在Chrome和Firefox之间建立视频通话。&/p&&p&这也是我写这篇文章的原因。Edge在ORTC中对H.264的支持并不多。从更大的视角来看,这甚至谈不上有意义。相比于其他浏览器Edge几乎没有市场份额,那么为什么还要为它花费心思呢?但是这件事仍然标志着一个转折——我们应当问自己:当我们要开发一个基于WebRTC的产品时,我们应该选择什么样的视频编解码器。&/p&&p&去年的时候,这个答案可能是“VP8”。&/p&&p&几个月前,答案可能是“看情况”。&/p&&p&现在,答案将会是“除非必须用VP8,否则就用H.264”。&/p&&p&如下,就是这一切发生的四个原因:&/p&&p&&b&1. &/b&&b&浏览器互操作基准&/b&&/p&&p&如果你希望你的服务能够覆盖尽可能多的浏览器,并且需要视频功能,那么H.264是你正确的选择。再过几个月, H.264将获得所有浏览器厂商的官方支持,并就此一锤定音。此外,你可以期待苹果首先使用H.264并接下来考虑使用VP8,就像微软现在在Edge上所做的那样。&/p&&p&&b&2. &/b&&b&移动领域&/b&&/p&&p&相比于VP8,移动设备更喜欢H.264。视频编解码器消耗相当多资源;为克服这个问题,移动设备使用硬件加速来进行视频编解码。他们都拥有H.264视频加速能力,尽管开发者并不总是能够对此进行编程。许多移动设备商对VP8知之甚少,这归结为移动设备上的WebRTC需要用软件方式实现VP8。&/p&&p&基于这个原因,一些开发者在移动设备上用H.264替换VP8,特别是针对那些只在移动设备上运行的产品。 &/p&&p&虽然我相信在新的芯片上VP8的性能正在提升,但是在已经存在的数百万个移动设备上支持VP8仍然是个麻烦问题。既然现在所有浏览器都以各种方式支持H.264,那么开发者还有什么动机去支持那些必须使用VP8的移动应用呢?&/p&&p&&b&3. &/b&&b&遗留视频系统&/b&&/p&&p&遗留视频系统主要是视频会议系统,他们使用H.264编解码器,绝大多数不支持VP8。直到今天,他们仍然通过一种特别的网关(MCU)支持WebRTC,或者根本就不支持。&/p&&p&视频转码是WebRTC连通遗留视频系统的主要障碍之一,这非常消耗资源。直接让H.264在运行在各系统上是最容易的办法,也是当前就可以实现的办法。&/p&&p&这也是思科用Spark连通Firefox的原因。思科决定在WebRTC中使用H.264,而不是对VP8进行转码。&/p&&p&&b&4.&/b&&b&流量&/b&&/p&&p&互联网上超过60%的流量都是视频。这其中大部分不是实时视频,而是像YouTube或者Netflix这样的非实时视频。&/p&&p&如今视频流基本上都是H.264,某些情况下是VP9(YouTube使用VP9编码)。&/p&&p&在iPhone上获取视频内容需要HLS协议,这再次意味着使用H.264编解码器。&/p&&p&因此我们面临两种选择:当我们想输出视频流时,是把WebRTC生成的视频内容转码成H.264,还是直接在开始就使用H.264生成视频内容。 &/p&&p&&b&你是否需要关注&/b&&/p&&p&如果你的视频服务是一对一的会话服务,没有服务器端做视频处理,那么你大可不必关注。在这种场景下,浏览器的最终协商结果对你来说已经足够好了,并且很有可能是该特殊场景下的最佳选择。&/p&&p&如果厂商在服务端视频处理针对VP8进行大量投入,包括视频录制、混合、路由等,那么把这些服务端设备进行改造使其支持H.264可能很重要。对他们来说,转向H.264可能是一个困难的决定,但却是不得不做的决定。&/p&&p&&b&WebRTC&/b&&b&视频编解码器的未来&/b&&/p&&p&一旦我们放眼未来,我们可能需要关注VP9。&/p&&p&然后就是开放媒体联盟,他们致力于开发一款广泛使用的下一代免专利视频编解码器。我在最近的每月在线会议上更新过他们的进度。&/p&&p&
作为纪录,我相当讨厌H.264和它代表的一切。但是现在必须承认, 它留了下来,和WebRTC一起发展。&br&&/p&&blockquote&更多资料可关注官方公众号:编风网(微信ID:befoio)或 WebRTC编风网(微信ID:webrtcorgcn)&/blockquote&
H.264被设定为取代VP8成为WebRTC服务的视频编解码器。微软上周在他们的Edge开发博客上宣布, Edge的ORTC开始支持H.264/AVC。 · 是的,它是ORTC而不是WebRTC · 是的,它仅通过运行时标志就可以开启 · 是的,它只在Edge浏览器可用,IE浏览器不行但话又说回…
本文主要内容来自于&a href=&https://link.zhihu.com/?target=http%3A//book.mixu.net/css/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&learn CSS layout&/a& 和&a href=&https://link.zhihu.com/?target=https%3A//www.w3.org/TR/CSS21/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&CSS2.1 spec&/a& 和&a href=&https://link.zhihu.com/?target=http%3A//www.imooc.com/u/197450/courses%3Fsort%3Dpublish& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&深入理解CSS系列&/a& 和《CSS权威指南》,主要讲解一些核心的css概念(起这么个名字感觉会被人打)&p&你可能听说过CSS常规流(norm flow)中的inline和block。但是你知道在CSS中block和inline元素的相对位置并不由display属性决定吗?其实际上由formatting context决定,其同时受到兄弟元素的影响。&/p&&p&你可能使用过z-index来固定元素的相对层叠顺序。但是你知道z-index在文档中并不是绝对的顺序,相反其是相对于层叠上下文的?&/p&&p&你可能听过盒子模型。但是你知道事实上存在至少5种盒子模型吗?其区别在于如何处理内容大小和margin:auto属性,读完本文后你就会知道了。&/p&&p&CSS布局学起来很难,你从无数的网站学习到很多布局小技巧但是你却从未理解背后的布局算法。&/p&&p&元素的布局信息事实上由位置大小层叠位置决定,你一旦了解了如何决定这些信息,你就理解了布局算法。&/p&&h2&一:CSS的盒子位置&/h2&&p&CSS布局的核心在于如何将一系列HTML元素映射到一组盒子上,这些盒子的被放在x-y-z坐标系里。&/p&&p&盒子的x-和y-坐标事实上由布局方案(positioning scheme)决定。本章中,我会详细讨论CSS2.1中引入的positioning scheme:normal flow,floats和absolute positioning。&/p&&p&概念上来说,CSS布局的最高抽象就是positioning scheme。一旦positioning scheme决定了,其可以进一步的被特殊的layout modes修改,这些layout modes包括display:table,display:inline-table。即使在CSS3的扩展中,其引入了其他的layout modes包括flexbox和grid,其仍然处于上述的positioning scheme中(如display:flex和display:inline-flex);&/p&&h2&Positioning schemes&/h2&&p&CSS2.1定义了三种positioning scheme,其包括:&/p&&ul&&li&normal flow,其包含三种formatting contexts:block,inline和 relative formatting context&/li&&li&floats:其与normal flow互动,其构成了现代CSS grid framework基础&/li&&li&absolute positioning,其处理absolute 和fixed元素相对于normal flow的定位&/li&&/ul&&p&positioning scheme对 x-axis 和 y-axis元素定位有重大影响。所有的元素除非通过设置float和position属性从normal中移除,默认属于normal flow。&/p&&p&&figure&&img src=&https://pic3.zhimg.com/v2-bec6fcbae70d4be0ae15f9_b.jpg& data-rawwidth=&774& data-rawheight=&153& class=&origin_image zh-lightbox-thumb& width=&774& data-original=&https://pic3.zhimg.com/v2-bec6fcbae70d4be0ae15f9_r.jpg&&&/figure&通过它们与normal flow元素的交互方式能更好的理解float和absolute positioning,所以我先说明normal flow。&/p&&p&仔细想下,事实上layou存在两方面在起作用:&/p&&ul&&li&元素的盒子大小和对齐方式,其通常由display的属性(width,height,margin)控制&/li&&li&一个特定父元素的子元素是如何相对于彼此放置的&/li&&/ul&&p&一个父元素的子元素的相对位置是通过父元素为子元素建立的formatting context控制的,在normal flow中,可以使block formatting context或者inline formatting context。&/p&&blockquote&哈哈哈,这里终于到了鼎鼎大名的bfc(block formatting context),简单来说,bfc就是normal flow中的一种formatting context。所以触发bfc这种说法根本来说就是错误的,更为准确的说法应该是建立了一个新的bfc(establish a new block formatting context)。鉴于bfc的迷惑性,在CSS3中已经被改为flowing root了。至于其种种神奇的作用(比如阻止margin collapse)则在于CSS中很多的特性均需要满足一定的前提,而对于margin collapse,其条件是&a href=&https://link.zhihu.com/?target=https%3A//www.w3.org/TR/CSS21/box.html%23collapsing-margins& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&collapsing-margins&/a&&br&&ul&&li&两者都为处于同一bfc下的 in-flow block-level boxes&/li&&li&两者间不存在line boxes,clearance,padding,border&/li&&li&都处于垂直相邻的盒子边缘&/li&&/ul&&p&这里的第一个条件是处于同一bfc下的盒子才可能发生margin collapse,那么假如父元素创建了新的bfc,那么父元素和子元素将不再处于同一bfc下(子元素处于父元素创建的新的bfc下),则可以阻止发生margin collpase,相反若子元素创建了新的bfc,那么子元素和父元素仍然处于同一bfc下,只是孙子元素处于新的bfc下,父元素和子元素仍然发生margin collapse,其效果如下所示&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&!DOCTYPE html&
&html lang=&en&&
&meta charset=&UTF-8&&
&title&Title&/title&
width: 100
height: 100
background:
margin: 10
height: 40
background:
margin-top: 50
.demo2 .parent{
.demo1 .son{
&div class='demo1'&
&div class=&parent&&
&div class=&son&&
&div class=&demo2&&
&div class=&parent&&
&div class=&son&&
&/code&&/pre&&/div&&p&渲染效果如下&/p&&p&&figure&&img src=&https://pic1.zhimg.com/v2-4e6eda6c4b3_b.jpg& data-rawwidth=&255& data-rawheight=&257& class=&content_image& width=&255&&&/figure&可以看出子元素创建了新的bfc但是并不能阻止margin collapse&/p&&p&所以bfc并不是高深莫测的东西,其和其他特性的结合才变得有趣。&/p&&/blockquote&&p&CSS2.1规范定义formatting context如下:&/p&&blockquote&normal flow里的box属于一个formatting context,其是block或者inline,但不能同时都是。block-level盒子参与bfc(block formatting context),inline-level盒子参与ifc(inline formatting context)&br&&/blockquote&&p&父元素(容器)根据子元素是inline-level还是block-level为其子元素建立formatting context。术语inline-leve和block-level用来强调display属性不为inline和block的盒子仍然可以属于这两种formatting context。例如display:table元素被认为是block-level而display:inline-table元素被认为是inline-level。&/p&&p&一个block-level的元素定义如下&/p&&blockquote&block-level元素是那些在文档中视觉表现为block的元素(例如paragraph)。display属性为‘block’,‘list-item'和’table'的元素是block-level&br&block-level的盒子就是参与bfc的盒子。每个block-level的元素都会生成一个主block-level box,其包含子孙盒子并且生成内容,它也是负责参与positioning scheme的盒子。一些block-level的元素也可能除了主盒子外还生成附加的盒子如‘list-item’元素。这些附加的盒子相对于主盒子放置。&/blockquote&&p&几乎所有的block盒子都是block container。一个block container就是一组其他盒子的parent并且有一个特定的formatting context:&/p&&blockquote&除了table boxes和替换元素,一个block-level的盒子也是一个block container 盒子。一个block container盒子或者仅包含block-level盒子或者创建了ifc即只包含inline-level盒子&br&&/blockquote&&p&一个inline-level元素定义如下:&/p&&blockquote&inline-level元素是那些在源文档中不构成块状内容的元素;这些内容被分散在各行之中(如inline images和&em&text&/em&等)。display为'inline','inline-table','inline-block'的元素是inline-level的。inline-level元素生成inline-level盒子,其参与ifc。&br&一个inline盒子是那些即是inline-level的&br&。。。。todo&/blockquote&&p&我不会讲替换元素和非替换元素的区别,因为其区别很小。最简单的看待替换元素的方法是把它们当做img或者video元素,即这些元素仅包含一个整体内容(外部环境定义)并且不能像文本内容那样被拆散成多行。&/p&&p&关于上面定义最有趣的地方在于每个盒子包含的formatting context要么是’inline formatting conext&要么是&block formatting context&。这既是说level每个父元素的所有参与布局的孩子元素只能使用其中一种formatting context。当你将如text的inline-level元素和如div的block-level元素混合使用时,这怎么可能办得到。答案就是inline-level元素可以被提升为block-level元素。这个机制就是匿名盒子生成。&/p&&h2&Anonymous box generation&/h2&&p&匿名盒子生成用于处理当一个父元素即含有inline-level盒子也含有block-level的情形(此时就会生成匿名盒子)和当标签包含了inline-level元素与包围文本的混合,如paragraph里嵌入em和i标签。&/p&&h2&Anonymous block boxes &/h2&&p&规范里给了如下例子,可得&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&div&
&p&More text
&/p&&/div&
&/code&&/pre&&/div&&blockquote&如果一个容器盒子(如上面div生成的盒子)内部有一个block-level盒子(如上面的P)那么我们强迫其内部有两个block-level盒子&br&&/blockquote&&p&规范里提供了如下的描述阐明匿名盒子如何包裹inline-level内容&/p&&figure&&img src=&https://pic4.zhimg.com/v2-e8c4c4a7ffdb0c23d3f2320_b.jpg& data-rawwidth=&334& data-rawheight=&204& class=&content_image& width=&334&&&/figure&&blockquote&当一个inline盒子包含一个in-flow的block-level的盒子,那么inline盒子(和其同一行的祖先盒子)会被打散围绕着block-level盒子(且任何的block-level兄弟都是连续的或者被collapsible whitespace或者out-of-flow元素分割)&br&todo&/blockquote&&p&简单来说,当一个inline-level和block-level盒子混杂在一个父元素内部时,inline-level盒子被拆散围绕在block-level盒子并且其内容被匿名block-level盒子包裹。&/p&&h2&Anonymous inline boxes&/h2&&p&当一个block container包含文本并且这些文本没有被包含在inline-level元素里时会生成匿名内联盒子(anonymous inline boxes)。例如如下标记&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&p&Some &em& emphasized &/em& text &/p&
&/code&&/pre&&/div&&p&会生成两个匿名内联盒子,一个包含“Some&,一个包含”text“.&/p&&p&匿名盒子生成非常重要,因为其决定了该为在normal flow中包含block 和inline-level的元素生成何种formatting context。许多现实中的HTML布局里的一个父元素既含有block-level也含有inline-level内容。匿名盒子生成可以保证如果任何的block-level被混入inline-level的兄弟元素时,那么inline-level盒子会被包裹进一个匿名block-level容器内,这也意味着它们将被视为block-level元素相对于其他盒子布局。&/p&&p&既然我们知道了如何确定formatting context,那么我们接下来看如何进行布局。&/p&&h2&Normal flow positioning&/h2&&p&在normal flow中,一个父盒子内的子盒子是按照formatting context布局的。normal flow中的两个formatting context大致对应于垂直排列和水平排列&/p&&h2&Normal flow: block formatting&/h2&&p&规范为bfc下如何布局提供了很好的说明&/p&&blockquote&在blocking formatting context中,盒子一个接一个,垂直的,自顶向下的排列。两个相邻的盒子之间的距离由由margin属性确定。相邻block-level盒子的垂直的margin可能发生重叠&br&在block formatting· context下,每个盒子的左外边缘触碰到containing block的左边缘(对于right-to-left formatting· context,右边缘相邻)。这甚至适用于存在floats的情形(尽管一个盒子的line boxes可能由于floats收缩),除非盒子建立了一个新的block formatting context(此时盒子本身可能由于floats收缩)。&br&下面的demo可以解释上面的话&/blockquote&&p&最重要的两个结论是在bfc下盒子是垂直排列的,而且每个盒子的左边缘会触碰到containing box的左外边(即使在floats存在的情况)&/p&&p&下面的代码何以演示这个规则:&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&.float {
padding-top: 10
width: 30%;
width: 40%;
&div class=&container violet&&
&div class=&float red&&float&/div&
&div class=&foo blue&&foo&/div&
&div class=&bar green&&bar&/div&
&div class=&baz orange&&baz&/div&
&/code&&/pre&&/div&&p&&figure&&img src=&https://pic4.zhimg.com/v2-cab48f19aa6d8a43a573_b.jpg& data-rawwidth=&591& data-rawheight=&162& class=&origin_image zh-lightbox-thumb& width=&591& data-original=&https://pic4.zhimg.com/v2-cab48f19aa6d8a43a573_r.jpg&&&/figure&上面的例子中&/p&&ul&&li&每个block盒子都在containing box的左外边缘&/li&&li&即使存在float也不影响其在左外边缘的位置,除了会造成文本的偏移&/li&&li&foo对应的block box(没有明确的设置宽度)宽度扩展为容器宽度&/li&&li&另外两个设置宽度的盒子,从左边缘扩展&/li&&li&另外两个盒子并没有在一行,即使其能够塞进一行&/li&&/ul&&p&总的来说,bfc比较简单,用几个段落就可说清,但是ifc并非如此&/p&&h2&Normal flow: inline formatting(&b&TL;DR&/b& )&/h2&&p&ifc相当复杂,更复杂的细节以后再补充。。。&/p&&p&ifc比较复杂,因为其涉及到将内容拆分为line boxes,这是一个你不能从标记直接看出来的结构其是根据内容生成的&/p&&blockquote&在ifc中,盒子在containing box里被一个接一个,自上而下的水平放置。水平的margin,borders,和padding散布在这些box之间。&br&&br&这些盒子可以以不同的方式垂直放置:其底部和顶部可能是对齐的。包含这些盒子的方形区域构成了一行即行框(line box)&br&&br&line box的宽度由containing box的宽度和是否存在float决定。line box的高度由下节的高度计算决定&/blockquote&&p&简单来说,在ifc中盒子水平的相邻排放。line box按需生成;其宽度通常为包含块的高度(减去floats)而且其高度足够包含其内部所有的盒子。特别的是&/p&&blockquote&一个line box的高度总是足够包含其含有的所有盒子,[...]当几个inline-boxes不能塞进一个line box时,其总是拆分为几个垂直排列的line boxes。因此,一个段落由一系列垂直排放的line boxes组成。line boxes之间没有垂直的分割(除非特别的指明)并且绝不重叠&br&&br&总之,line boxes的左边缘触及包含快的左边缘且右边缘触及包含块的右边缘。&br&如果因为存在float导致水平空间缩减那么line boxes宽度上可能有所差异。&br&同一ifc下的line boxes高度上也常有差异(比如一行可能包含高点的图片而另一行可能只有文本)&/blockquote&&p&当inline box太大以至于无法塞入一行怎么办?这取决于inline box是替换元素还是非替换元素:&/p&&blockquote&当一个inline box的宽度超出了line box的宽度,其将被拆分为几个盒子,并且这几个盒子将散布于各个line boxes。如果一个inline box不能够被拆分,那么这个inline box将溢出line box&br&当一个inline box被拆分,其margin,border和padding在拆分处并没视觉效果&/blockquote&&p&简而言之,当inline box超过了line box的宽度,其将会尽可能的拆分。当某些规则阻止拆分盒子,那么其将简单的溢出该line box&/p&&p&关于ifc最复杂的情况即line boxe是如何处理对齐的。text-align和vertical-align两个属性控制对齐&/p&&h3&Horizontal alignment within line boxes: text-align&/h3&&p&text-align属性控制inline-box如何在line box内对齐,&/p&&blockquote&text-align:left则左对齐,right则右对齐&br&&/blockquote&&p&注意到其仅适用于当line box含有空余空间的情形,而且你不能直接控制inline-level box在line box中是如何摆放的,标准规定:&/p&&blockquote&当inline-level box的宽度小于所在line box的宽度时,其在line box的水平分布取决于‘text-align'属性。如果该属性的值为'justify',那么UA(user agent)可以伸展inline boxes内的空格和文本。&br&&/blockquote&&p&换句话说,text-align属性仅在inline content的内容已经分布在line boxes之后才加以应用&/p&&blockquote&一块文本就是一组line boxes。'left','right'和'center'指明了inline-level盒子在line box中是如何对齐的,其对齐是相对于line box而非viewport。对与‘justify’,该性质表明inline-level盒子如果可能就尽可能通过扩展或缩小inline box的内容将其扩散至line-box的两侧,否则就按初始值对齐&br&&/blockquote&&p&通常来说,空白会受到justify属性影响,然而&/p&&blockquote&如果一个元素'white-space'的计算值(computed value)为'pre'或者'pre-wrap',那么该元素的glyph或者空白都不受justify的影响&br&&/blockquote&&h3&Vertical alignment within line boxes: vertical-align&/h3&&p&下面两个属性控制line box的垂直对齐&/p&&blockquote&vertical-align:默认值为baseline,控制盒子的垂直对齐,仅适用于inline(和table-cell)盒子&br&line-height:默认值为normal,规定了用于计算line box height的height&/blockquote&&p&vertical-align控制了line box内inline boxes的垂直对齐方式,而非line box自身的对齐方式。为了理解inline box是如何定位的,你需要首先理解line box和inline box的高度是如何计算的。&/p&&p&line box 的高度收到下面两个因素影响:&/p&&ul&&li&其包含的inline box的高度&/li&&li&其包含的inline box的对齐方式&/li&&/ul&&p&inline box(非替换元素)的高度按下面方式决定&/p&&blockquote&‘height'属性并不其起作用,内容区的高度是基于font的,但是规范没有规定是如何基于font的。UA可以例如使用em-box&br&inline(非替换元素)垂直的padding,border,margin与inline box的line-height的计算无关。但是当计算line-box的高度时只有line-height起作用。&br&正如你从规范所见,inline box的 的height由'font'和'line-height'。特别的是,每个font都必须定义一个baseline,一个text-top和一个text-bottom位置。inline box内容区域的高度等于font的高度乘以line-height的属性值&br&对于一个非替换 inline 元素,'line-height'规定了用于计算line box 高度的height&/blockquote&&p&'line-height'的值可以是绝对值也可以是相对于font height的相对值。其与父元素的高度并不相关,即使其值为百分数,其值可以取值如下:&/p&&blockquote&normal:用户代理定义的一个值,其值为相对于font的相对值,建议normal的取值为1.0到1.2之间。&br&length:绝对值用于计算line box的height,负值非法。&br&number:相对值,相对于元素的font size,不能取负值&br&percentage:相对值,相对于元素的 computed font size,不能取负值&br&&br&如果一个inline box里包含了多个font怎么办?&br&如果存在多个font,内容区的高度计算并未在规范中定义。但是我们建议内容区高度的计算应该对于(1)em-boxes (2) the maximum ascenders and descenders, of all the fonts in the element&/blockquote&&p&规范并未定义该值,但是建议其高度能够容纳所有使用的字体&/p&&p&inline box的对齐方式由属性'vertiacal'确定,其属性分为两组,第一组相对于父元素font的baseline,content area,或者是字体相关的sub和super,包括如下属性值&/p&&blockquote& baseline:&br&middle:&br&sub:&br&super:&br&text-top:&br&text-bottom:&br&percentage:&br&length:&/blockquote&&p&第二组相对于父元素的line box,这是一个递归算法,因为line box的height取决于vertical alignment而vertical alignment又取决于 line box。遇到这种互相递归的算法,肯定需要一个递归基,该算法的递归基就是第一组属性。这也意味着第二组属性值的元素的布局是在第一组属性值元素布局之后。第二组属性包括&/p&&blockquote&top:&br&bottom:&/blockquote&&p&总结来说inline box有如下属性:&/p&&ul&&li&font size:决定了字体的大小&/li&&li&line height:决定了inline box的高度&/li&&li&baseline:其由font确定&/li&&/ul&&p&而line box的高度计算步骤如下&/p&&ol&&li&计算line box内的所有inline boxes的高度&/li&&li&对所有vertical-align属性值为第一组的元素,应用vertical-align的属性值进行对齐&/li&&li&对所有vertical-align属性值为第二组的元素,应用vertical-align的属性值进行对齐&/li&&/ol&&p&对于line box有如下属性:&/p&&ul&&li&font size:继承自父元素&/li&&li&height:由line box内的inline box的height 和 alignment确定&/li&&li&baseline:通过'struct'定义:这是一个不可见,零宽的inline box,其含有font 和line height属性。&/li&&/ul&&p&一般来书父元素和子元素的font size是一样的,因此看不出line box基线和inline box的基线差别。&/p&&blockquote&注:table也有vertical-align属性,但是这个属性的工作方式完全不同,应该把其与这里的vertical-align区分开来&/blockquote&&h3&Normal flow: relative positioning&/h3&&p&既然我们已经讨论完bfc和ifc了,接下来可以讨论最后一个normal flow 布局 relative positioning了。&/p&&p&Relative positioning被认为是normal flow布局的一部分,因为其与normal flow没有太大差异。&/p&&blockquote&relative:盒子的位置完全基于normal flow计算,然后对盒子进行偏移。'position:relative'的属性对于table-row-group,table-header-group,table-footer-group,table-row,table-column-group,table-column,table-cell,和table-caption元素是未定义的。&br&&br&注:我发现理解relative positioning的最好方式是从渲染的角度考虑,我们发现'position:relative'属性几乎能和其他所有布局方式同时配合使用,而不会发生冲突,而position:absolute和float却不行(这两者实际发生冲突),原因在于position:relative的作用是发生在paint阶段,而其他布局则是发生在layout阶段。position:relative是在layout阶段完成后,在paint阶段进行偏移。(这只是一种理解方式很可能有错误)&/blockquote&
本文主要内容来自于 和 和 和《CSS权威指南》,主要讲解一些核心的css概念(起这么个名字感觉会被人打)你可能听说过CSS常规流(norm flow)中的inline和block。但是你知道在CSS中block和inline元素的相对位置并不…
已有帐号?
无法登录?
社交帐号登录
493 人关注
383 条内容
370 人关注
480 条内容
180 条内容

我要回帖

更多关于 手机下载微信打不开 的文章

 

随机推荐