Web开发是须要掌握多种技术。咱们习惯于与多种语言密切合做。并且,随着开发Web应用程序变得愈来愈广泛和差异细微化,咱们常常寻找创造性的方法来弥合这些语言之间的差距,从而使咱们的开发环境和工做流程更容易,更高效。css
最多见的示例一般是使用模板语言时。例如,可使用一种语言来生成更详细的语言(一般是HTML)的代码。这是前端框架的关键做用之一 -操做HTML。这个领域最出名的就是JSX,由于它不是真正的模板语言;它是JavaScript的语法扩展,它使得使用HTML很是简洁。前端
Web应用程序经历了许多状态组合,单独管理状态一般颇有挑战性。这就是为何CSS有时会被淘汰的缘由 - 即便经过不一样的状态和媒体查询管理样式一样重要且一样具备挑战性。在这个由两部分组成的系列中,我想将CSS放在聚光灯下,并探索弥合它与JavaScript之间的差距。在本系列中,我将假设您正在使用像webpack这样的模块解析器。所以,我将在个人示例中使用React,但相同或相似的原则适用于其余JavaScript框架,包括Vue。react
CSS领域正朝着多个方向发展,由于要解决许多挑战而且没有“正确”的路径。我一直在花费大量精力尝试各类方法,主要是在我的项目上,因此这个系列的目的只是告知,而不是给你解决方案。webpack
在深刻研究代码以前,有必要解释Web应用程序样式化方面最显着的挑战。 我将在本系列中讨论的是范围,条件和动态样式以及可重用性。程序员
做用域定是众所周知的CSS挑战,它的目的是编写不会影响到组件外部的样式,从而避免意外的反作用。 咱们但愿在不影响编码体验的状况下实现功能。web
虽然前端应用程序中的状态开始变得愈来愈先进,但CSS仍然是静态的。 咱们只能有条件地应用样式集 - 若是按钮是主要的,咱们可能会应用“primary”类并在单独的CSS文件中定义它的样式以应用它在屏幕上的样式。 有几个预约义的按钮变化是可管理的,但若是咱们想要有各类按钮,如为Twitter,Facebook,Pinterest定制的特定按钮,可能还会有其余不少种? 咱们真正想要作的只是传递颜色并使用CSS定义状态,如悬停,焦点,禁用等。这称为动态样式,由于咱们再也不在预约义样式之间切换 - 咱们不知道接下来会发生什么。 可能会想到内联样式来解决此问题,但它们不支持伪类,属性选择器,媒体查询等。前端框架
重用规则集,媒体查询等是我最近不多看到的一个主题,由于它已经被Sass和Less等预处理器解决了。 可是我仍然想在这个系列中再次提起它。微信
我将列出一些处理这些挑战的技术以及它们在本系列的两个部分中的局限性。 没有任何技术优于其余技术,它们甚至不相互排斥; 您能够选择一个或组合它们,具体取决于您的决定是否能改善您的项目质量。框架
咱们将使用名为Photo的示例组件演示不一样的样式技术。 咱们将呈现可能具备圆角的响应式图像,同时将替代文本显示为标题。 它会像这样使用:编辑器
<Photo publicId="balloons" alt="Hot air balloons!" rounded />
在构建实际组件以前,咱们将抽象出srcSet属性以保持示例代码简洁。 那么,让咱们建立一个带有两个实用程序的utils.js文件,用于使用Cloudinary生成不一样宽度的图像:
import { Cloudinary } from 'cloudinary-core' const cl = Cloudinary.new({ cloud_name: 'demo', secure: true }) export const getSrc = ({ publicId, width }) => cl.url(publicId, { crop: 'scale', width }) export const getSrcSet = ({ publicId, widths }) => widths .map(width => `${getSrc({ publicId, width })} ${width}w`) .join(', ')
咱们设置Cloudinary实例以使用Cloudinary的演示云名称,以及根据指定选项为图像publicId生成URL的url方法。 咱们只对修改此组件的宽度感兴趣。
咱们将分别将这些实用程序用于src和srcset属性:
getSrc({ publicId: 'balloons', width: 200 }) // => 'https://res.cloudinary.com/demo/image/upload/c_scale,w_200/balloons' getSrcSet({ publicId: 'balloons', widths: [200, 400] }) // => 'https://res.cloudinary.com/demo/image/upload/c_scale,w_200/balloons 200w, https://res.cloudinary.com/demo/image/upload/c_scale,w_400/balloons 400w'
若是你不熟悉srcset和sizes属性,我建议先阅读一下有关响应式图像的内容。 这样,您能够更轻松地按照示例进行操做。
CSS-in-JS是一种样式方法,它将CSS模型抽象到组件级别,而不是文档级别。 这个想法是CSS能够限定为特定组件 - 而且只限于该组件 - 以使这些特定样式不与其余组件共享或泄露到其余组件,而且仅在须要时才调用。 CSS-in-JS库经过在<head>
中插入<style>
标签在运行时建立样式。
使用这个概念的第一个库是JSS。 如下是使用其语法的示例:
import React from 'react' import injectSheet from 'react-jss' import { getSrc, getSrcSet } from './utils' const styles = { photo: { width: 200, '@media (min-width: 30rem)': { width: 400, }, borderRadius: props => (props.rounded ? '1rem' : 0), }, } const Photo = ({ classes, publicId, alt }) => ( <figure> <img className={classes.photo} src={getSrc({ publicId, width: 200 })} srcSet={getSrcSet({ publicId, widths: [200, 400, 800] })} sizes="(min-width: 30rem) 400px, 200px" /> <figcaption>{alt}</figcaption> </figure> ) Photo.defaultProps = { rounded: false, } export default injectSheet(styles)(Photo)
乍一看,样式对象看起来像用对象表示法编写的CSS,带有附加功能,好比传递一个函数来设置基于props的值。 生成的类是惟一的,所以您永远没必要担忧它们与其余样式冲突。 换句话说,你能够自由的使用做用域! 这就是大多数CSS-in-JS库的工做方式 - 固然,咱们将在功能和语法方面进行一些改进。
您能够经过属性看到渲染图像的宽度从200px开始,而后当视口宽度变为至少30rem时,宽度增长到400px宽。 咱们生成了额外的800宽度,以覆盖更大的屏幕密度:
styled-components是另外一个CSS-in-JS库,可是使用更熟悉的语法巧妙地使用模板文字而不是对象看起来更像CSS:
import React from 'react' import styled, { css } from 'styled-components' import { getSrc, getSrcSet } from './utils' const mediaQuery = '(min-width: 30rem)' const roundedStyle = css` border-radius: 1rem; ` const Image = styled.img` width: 200px; @media ${mediaQuery} { width: 400px; } ${props => props.rounded && roundedStyle}; ` const Photo = ({ publicId, alt, rounded }) => ( <figure> <Image src={getSrc({ publicId, width: 200 })} srcSet={getSrcSet({ publicId, widths: [200, 400, 800] })} sizes={`${mediaQuery} 400px, 200px`} rounded={rounded} /> <figcaption>{alt}</figcaption> </figure> ) Photo.defaultProps = { rounded: false, } export default Photo
咱们常常建立语义中性元素,如<div>
和<span>
,仅用于样式目的。这个库以及许多其余库容许咱们在一个动做中建立和设置它们。
我最喜欢这种语法的好处是它就像常规的CSS,减去插值。这意味着咱们能够更轻松地迁移CSS代码,而且咱们可使用现有的css知识,而没必要熟悉在对象语法中编写CSS。
请注意,咱们能够在咱们的样式中插入几乎任何东西。此特定示例演示了如何将媒体查询保存在变量中并在多个位置重用它。响应式图像是一个很好的用例,由于sizes属性基本上包含CSS,因此咱们可使用JavaScript来使代码更简洁。
假设咱们决定在视觉上隐藏字幕,但仍然可让屏幕阅读器访问它。我知道实现这一目标的更好方法是使用alt属性,但为了这个例子,让咱们使用不一样的方式。咱们可使用一个名为polished的样式mixin库 - 它适用于CSS-in-JS库,很是适合咱们的示例。这个库包含一个名为hideVisually的mixin,它正是咱们想要的,咱们能够经过插入它的返回值来使用它:
import { hideVisually } from 'polished' const Caption = styled.figcaption` ${hideVisually()}; ` <Caption>{alt}</Caption>
即便hideVisually输出一个对象,样式组件库也知道如何将其做为样式进行插值。
CSS-in-JS库具备许多高级功能,如主题,供应商前缀甚至内联关键CSS,这使得彻底中止编写CSS文件变得容易。 此时,您能够开始了解为何CSS-in-JS成为一个诱人的概念。
CSS-in-JS的明显缺点是它引入了一个运行时:须要经过JavaScript加载,解析和执行样式。 CSS-in-JS库的做者正在添加各类智能优化,如Babel插件,但仍然存在一些运行时成本。
一样重要的是要注意PostCSS没有解析这些库,由于PostCSS不是设计用于运行时的。许多人使用stylis做为结果,由于它更快。这意味着咱们遗憾的是没法使用PostCSS插件。
我要提到的最后一个缺点是工具。 CSS-in-JS正在以很是快的速度发展,文本编辑器扩展,linters,代码格式化等等须要追赶新功能以保持同等水平。例如,人们正在使用VS Code扩展样式组件来表示相似情感的CSS-in-JS库,即便它们并不是都具备相同的功能。我甚至看到提议功能的API选择受到保留语法突出显示的目标的影响!
有两个新的CSS-in-JS库,Linaria和astroturf,它们经过将CSS提取到文件中来管理零运行时。 它们的API相似于样式组件,但它们的功能和目标各不相同。
Linaria的目标是经过内置函数(如做用域,嵌套和供应商前缀)来模仿CSS-in-JS库的API,如样式组件。 相反,astroturf是基于CSS模块构建的,具备有限的插值功能,并鼓励使用CSS生态系统而不是使用JavaScript。
CSS-in-JS是一体化的样式解决方案,用于弥合CSS和JavaScript之间的差距。 它们易于使用,而且包含有用的内置优化 - 但全部这些都须要付出代价。 最值得注意的是,经过使用CSS-in-JS,咱们基本上从CSS生态系统中退出并使用JavaScript来解决咱们的问题。
零运行时解决方案经过恢复CSS工具来缓解一些缺点,这些工具将CSS-in-JS讨论提高到更有趣的水平。 与CSS-in-JS相比,预处理工具的实际限制是什么? 这将在本系列的下一部分中介绍。
建立了一个程序员交流微信群,你们进群交流IT技术
若是已过时,能够添加博主微信号15706211347,拉你进群