我们如何构建EQCSS以及为什么您也应该尝试构建自己的Polyfills

tech2022-12-07  118

背景故事 (The Backstory)

In 2013, I was creating the frontend of a responsive web app that had a lot of data to display. I had done a lot of responsive design using @media queries, but as I found myself trying to re-use components from one layout in another layout, I wished I could make my responsive breakpoints correspond to the width of the elements instead of the width of the browser.

2013年,我正在创建一个响应式Web应用程序的前端,该应用程序需要显示大量数据。 我已经使用@media查询完成了很多响应式设计,但是当我发现自己试图重用另一个布局中一个布局的组件时,我希望我可以使响应式断点对应于元素的宽度而不是宽度浏览器。

This is something CSS can’t currently do, so I was copying and pasting a lot of styles from template to template, changing mostly just the breakpoints. I searched for existing workarounds, mainly tools and JavaScript plugins, to help me automate this process or output the duplicate code for me — but these all seemed like imperfect solutions to the problem.

CSS目前无法做到这一点,所以我在模板之间复制并粘贴了很多样式,大部分只是更改了断点。 我搜索了现有的变通办法,主要是工具和JavaScript插件,以帮助我自动化该过程或为我输出重复的代码-但这些似乎都不是解决问题的完美方法。

I had heard about Less, a CSS preprocessor that lets you author CSS that includes extra features like variables and functions that aren’t part of standard CSS. You can add a small JavaScript plugin on your website that will allow the browser to read this non-standard CSS, and all your non-standard code would magically translate to styles that the browser understood. I started to wonder if there was a way I could extend CSS in the same way to solve my problem!

我听说过Less ,这是一个CSS预处理程序,可让您编写CSS,该CSS包含不属于标准CSS的变量和函数之类的额外功能。 您可以在网站上添加一个小JavaScript插件,使浏览器可以读取此非标准CSS,并且所有非标准代码都可以神奇地转换为浏览器可以理解的样式。 我开始怀疑是否有一种方法可以用扩展CSS的方式来解决我的问题!

插件的诞生 (The Birth of a Plugin)

Somewhere along the way, my paths crossed with an amazing and creative coder named Maxime. I had been a big fan of some of Maxime’s past projects, and he had knowledge and understanding of CSS and JavaScript far beyond mine. One day, when I was thinking about my challenges with CSS, I sent him the following message:

一路上的某个地方,我遇到了一位叫马克西姆(Maxime)的惊人而富有创造力的编码员。 我一直是Maxime过去项目的忠实拥护者 ,他对CSS和JavaScript的了解和了解远远超出了我的范围。 有一天,当我考虑使用CSS的挑战时,我给他发送了以下消息:

I need a way of writing CSS styles that lets me:

我需要一种写CSS样式的方法,该方法可以让我:

specify different styles based on the current width of an element

根据元素的当前宽度指定不同的样式 specify different styles based on the current height of an element

根据元素的当前高度指定不同的样式 keep an element vertically centered within its parent element at all times

始终保持元素在其父元素内垂直居中 keep an element horizontally centered within its parent element at all times

始终保持元素在其父元素内水平居中 specify different styles based on the text length of an element

根据元素的文本长度指定不同的样式 specify different styles based on number of child elements an element contains

根据元素包含的子元素的数量指定不同的样式

Bonus: to allow me to navigate up the DOM using the < selector

奖励:允许我使用<选择器浏览DOM

If I had a library like this I believe I could design layouts that would be truly bulletproof and unbreakable. I need @element queries!

如果我有这样的图书馆,我相信我可以设计出真正防弹且坚不可摧的布局。 我需要@element查询!

Is it possible to write these styles in a way that looks familiar to people who write CSS, but gets read and executed by JavaScript?

是否可以以编写CSS的人看似熟悉但被JavaScript读取和执行的方式编写这些样式?

Is JavaScript able to parse text (maybe called .jss file or <script type="text/jss"> where I could write CSS blocks, but wrap them with special @element queries, which could be read by JavaScript, and have the computed styles applied to the page?

JavaScript是否能够解析文本(可能称为.jss文件或<script type="text/jss"> ,我可以在其中编写CSS块,但用特殊的@element查询将它们包装起来, @element查询可以被JavaScript读取并进行计算样式应用于页面?

@element('.widget-box', min-height: 500px) { .widget-box { background: red; } .widget-box a { font-size: 18pt; } } @element('.widget-box', min-height: 500px) { .widget-box { background: red; } .widget-box a { font-size: 18pt; } }

or

要么

@element('#username', min-length: 20) { #username { font-size: 8pt; } #username < label { border: 1px solid red; } }

For this to be truly useful, it needs to have a small learning curve for people who already know CSS but don’t know JavaScript. They should be able to add the JavaScript library to a site and write the custom styles and have it work without needing any custom JavaScript. I guess that makes this more like a polyfill than a plugin : )

为了使它真正有用,对于已经了解CSS但不了解JavaScript的人,它需要有一条很小的学习曲线。 他们应该能够将JavaScript库添加到站点并编写自定义样式,并且无需任何自定义JavaScript就能使其工作。 我想这使它更像是一个polyfill而不是一个插件:)

Is something like this possible?

这样的事情可能吗?

— Tommy, December 5, 2014

—汤米,2014年12月5日

I wasn’t sure what kind of answer I would get back. I had already tried building a few plugins on my own without much success. Being a JavaScript beginner, I was very limited in what I was able to build on my own, and all of the solutions I had attempted to create myself had ended up adding more work. For a solution to be truly valuable, it should reduce my overall workload and make it easier to develop — it should be removing constraints, not adding them!

我不确定我会得到什么样的答案。 我已经尝试过自己构建一些插件,但没有取得太大的成功。 作为一个JavaScript的初学者,我很什么我是能够建立我自己的限制,所有的解决方案,我曾试图创建自己已经结束了加入更多的工作。 为了使解决方案真正有价值,它应该减少我的整体工作量并使开发更容易-应该删除约束 ,而不是添加约束 !

Quickly, I got an answer back from Maxime:

很快,我从Maxime得到了一个答案:

The answer to all your questions is yes. It’s possible. :)

您所有问题的答案是肯定的。 这是可能的。 :)

I don’t see one mission in your description, but three:

我在您的描述中看不到一项任务,但有三项:

You want to extend the CSS capabilities to do what media queries don’t do yet: apply some style to an element depending on its size or the length of its text content

您想扩展CSS功能以执行媒体查询尚未完成的工作:根据元素的大小或文本内容的长度,对元素应用某种样式

You want to extend CSS selectors to add a parent selector.

您要扩展CSS选择器以添加父选择器。

You wand to extend regular flow-related css properties by adding a way to vertical align anything into anything. Those are the 3 holy grails of CSS, you’re setting the bar very high :D

您可以通过添加将所有内容垂直对齐的方法来扩展与流相关的常规CSS属性。 这些是CSS的三大法宝,您将标准设置得很高:D

— Maxime, December 5, 2014

— Maxime,2014年12月5日

In the weeks that followed, through emails bouncing between Canada, France, and the United States, Maxime and I worked out what this new syntax would look like. We wrote and shared code in a language that didn’t exist yet, talked about potential problems and workarounds, and in the end, he built the first version of the EQCSS JavaScript plugin according to what I thought I needed.

在随后的几周中,通过在加拿大,法国和美国之间回弹的电子邮件,马克西姆和我弄清了这种新语法的模样。 我们用一种尚不存在的语言编写和共享了代码,讨论了潜在的问题和解决方法,最后,他根据我的需要构建了EQCSS JavaScript插件的第一个版本 。

Very shortly, I was able to put this plugin to use on the websites I was working on, and by January 2015, it was first used in production. We continued to experiment with it, adding new features and improving support and performance over the following months. Since the plugin was originally written, I’ve learned enough JavaScript to be able to troubleshoot, repair, maintain, and even add new features of my own.

很快,我就可以在正在使用的网站上使用此插件,到2015年1月,它首次在生产环境中使用。 我们继续进行试验,在接下来的几个月中增加了新功能并改善了支持和性能。 自从最初编写该插件以来,我已经学到了足够JavaScript,可以进行故障排除,修复,维护,甚至添加自己的新功能。

为什么我建立一个插件 (Why I Built a Plugin)

When I think of the reasons why I spent so much time and effort creating a solution like this, I think there were a few different motivations. The first was that I wanted a solution to the problems I was facing in my work every day; something I could put to use immediately that would start to save me time from the first day I used it.

当我想到花这么多时间和精力来创建这样的解决方案的原因时,我认为有一些不同的动机。 首先是我想要解决每天在工作中遇到的问题; 我可以立即使用的东西从我使用第一天起就开始为我节省时间。

Another motivation was to discover how malleable the web was as a platform. Was it possible to modify and extend one of the foundational languages of the web (CSS) and add new features to it yourself? How far could you take it?

另一个动机是发现网络作为平台的可塑性。 是否可以自己修改和扩展Web(CSS)的基本语言之一并为其添加新功能? 您能走多远?

Those reasons were enough to get me started initially, but now that we have a solution that competes well against other solutions, there’s also the additional motivation: can we refine our solution and present a more standardized method for solving similar problems so that everyone can benefit?

这些原因足以使我起步,但是现在我们有了一个可以与其他解决方案竞争良好的解决方案,还有另外的动力:我们可以完善我们的解决方案并提出一种更为标准化的方法来解决类似问题,以便每个人都能从中受益?

构建插件的挑战 (The Challenges of Building a Plugin)

There have been a number of challenges I have faced when creating this project. Some with the syntax itself, some with writing a plugin, some with maintaining support with different browsers as they change features, and some in the human arena, helping people to understand the concepts and make the most of what the plugin has to offer.

创建此项目时,我面临许多挑战。 有些使用语法本身,有些使用编写插件,有些在更改功能时保持对不同浏览器的支持,有些则在人的领域,以帮助人们理解概念并充分利用插件所提供的功能。

语法挑战 (Syntax Challenges)

Some of the syntax challenges we faced were trying to keep all of the syntax limited to just one language: CSS. We didn’t want the user to have to add anything extra to their HTML markup for the code they were writing in their CSS to work, and we wanted to avoid the user needing to write custom JavaScript themselves to get started.

我们面临的一些语法挑战试图将所有语法限制为仅一种语言:CSS。 我们不希望用户为在CSS中编写的代码工作而在HTML标记中添加任何额外内容,并且我们希望避免用户需要自己编写自定义JavaScript才能上手。

Another challenge was designing the syntax to be expressive enough to handle the use cases we needed to support right away while providing sufficient flexibility to allow users to write in their own additional functionality as needed. This extra flexibility has been a benefit to us when testing and adding new features because a prototype can be produced by writing custom code with the plugin in a way that translates closely to the code that would need to be added to the plugin to extend it. The plugin can be used to prototype new features for itself, and since we have introduced this additional flexibility, the speed at which we’ve been able to add new features has increased.

另一个挑战是将语法设计为足够表达,以处理我们需要立即支持的用例,同时提供足够的灵活性以允许用户根据需要编写自己的附加功能。 在测试和添加新功能时,这种额外的灵活性对我们是有益的,因为可以通过使用插件编写自定义代码来生成原型,这种方式可以紧密转换为需要添加到插件中以对其进行扩展的代码。 该插件可以用来为自己的新功能创建原型,并且由于我们引入了这种额外的灵活性,因此我们增加新功能的速度得以提高。

When inventing any new language feature, like we were doing with CSS, it’s important to design your syntax in a way that makes it future-proof, in case similarly-named features are added to the language in the future that work differently from your implementation. With our plugin, the custom syntax can be read from CSS, but the syntax can also be loaded directly from the plugin as a separate script type that the browser won’t try to read as CSS. Because of this custom script type, new terms in our syntax could coexist in the same codebase alongside other languages that include similar terms without them conflicting.

在发明任何新的语言功能时(例如我们在CSS上所做的工作),设计语法时必须确保其面向未来,这一点很重要,以防将来将来在该语言中添加名称相同的功能而与您的实现方式有所不同。 使用我们的插件,可以从CSS读取自定义语法,但是也可以将其作为单独的脚本类型直接从插件加载,浏览器不会尝试将其读取为CSS。 由于这种自定义脚本类型,我们语法中的新术语可以与包含相似术语的其他语言在同一代码库中共存,而不会发生冲突。

插件挑战 (Plugin Challenges)

One of our goals when trying to build a plugin (something I had never done at this scale before) was that we wanted to keep the file size reasonably small and keep the source code straightforward enough to allow anyone to read, edit and extend the plugin for their needs. It was also important to me that the features we added work in Internet Explorer 8. The amount of IE8-specific code this required ended up comprising a large portion of the overall codebase, but we were able to structure the plugin in a way that all of the IE8-specific code could be quarantined into its own file. This additional file only needs to be included in projects where IE8 support is required and can safely be omitted in projects where IE8 support is not needed.

尝试构建插件时,我们的目标之一(我以前从未在此规模上做到过)是我们希望将文件大小保持得足够小,并使源代码足够直接,以允许任何人读取,编辑和扩展插件为他们的需要。 对我来说也很重要,我们添加的功能可以在Internet Explorer 8中使用。所需的IE8特定代码最终占整个代码库的很大一部分,但是我们能够以一种所有特定于IE8的代码可以隔离到其自己的文件中。 仅在需要IE8支持的项目中才包含此附加文件,而在不需要IE8支持的项目中可以安全地省略此附加文件。

浏览器挑战 (Browser Challenges)

When designing a plugin that needs to work in web browsers, you begin to view web browsers as moving targets. We had originally built and tested the plugin in Chrome, Safari, Firefox and Internet Explorer, and it at first it was legacy versions of Internet Explorer that imposed the strictest limitations on the plugin. But in early 2016, after the plugin had been in production for a year, we received a bug report that in new versions of Firefox, some pages with the plugin were suffering a major performance issue! We hadn’t changed anything in our code — but after investigating different Firefox releases for this bug, it seemed like something had changed in the way Firefox thought about the page scroll event, and it was triggering recalculations in our plugin many more times than necessary.

设计需要在Web浏览器中工作的插件时,您开始将Web浏览器视为移动目标。 我们最初是在Chrome,Safari,Firefox和Internet Explorer中构建并测试该插件的,而最初,是Internet Explorer的旧版对该插件施加了最严格的限制。 但是在2016年初,该插件投入生产一年后,我们收到了一个错误报告,即在新版本的Firefox中,带有该插件的某些页面遭受了重大的性能问题! 我们没有更改代码中的任何内容-但是在针对此错误调查了不同的Firefox版本之后,似乎Firefox考虑页面滚动事件的方式发生了某些变化,并且它触发了插件中的重新计算次数超过了必要次数。

The proposed solution for fixing Firefox was to add a debounce mechanism to our plugin — a piece of code that could set an upper limit on how frequently a recalculation could be requested. This would solve our problem in Firefox, but in a way that affected how the plugin would work in all browsers, potentially opening up unforeseen issues. Making things worse, while testing solutions in prerelease versions of Firefox the problem seemed to be absent from versions of Firefox that were months away from release. It was stressful knowing other people were using our plugin and that unless we released a patch, Firefox users around the world would see a degraded experience for months. In the end, after a lot of testing, we released a patch adding a debounce mechanism, fixing the bug for Firefox users and increasing performance in other browsers as well.

修复Firefox的建议解决方案是在我们的插件中添加一个反跳机制-一段代码可以为请求重新计算的频率设置上限。 这可以解决我们在Firefox中的问题,但是会以某种方式影响插件在所有浏览器中的工作方式,从而可能带来无法预料的问题。 更糟糕的是,在Firefox的预发行版中测试解决方案时,似乎离发行版本还差几个月的Firefox版本似乎没有这个问题。 知道其他人正在使用我们的插件非常令人感到压力,除非我们发布补丁,否则全球Firefox用户将在几个月内看到降级的体验。 最后,经过大量测试,我们发布了一个补丁,其中添加了反跳机制,修复了Firefox用户的错误并提高了其他浏览器的性能。

模块挑战 (Module Challenges)

Originally, we had built the plugin to work like a polyfill (or a shim). It was designed to run directly in the browser, which made it easy to host on a CDN. It wasn’t long before we began getting requests from Webpack users who were building projects using JavaScript modules and wanted a version of plugin packaged as such. Thankfully, we were able to wrap the existing plugin with code from a UMD module template, which turned it into a module. The plugin can now be loaded by module loaders like Webpack and Browserify. Just as before, if you load the plugin outside of a module loader (like linking to the file directly in the browser) the plugin will still attach itself to the global object (the browser) just like it did before and run normally.

最初,我们已经构建了插件,使其可以像polyfill(或shim)一样工作。 它被设计为直接在浏览器中运行,从而使其易于在CDN上托管。 不久之后,我们就开始收到来自Webpack用户的请求,这些用户正在使用JavaScript模块构建项目,并希望使用这样的插件版本。 幸运的是,我们能够使用UMD模块模板中的代码包装现有插件,从而将其转换为模块。 该插件现在可以由Webpack和Browserify等模块加载器加载。 和以前一样,如果您在模块加载器之外加载插件(例如直接在浏览器中链接到文件),则插件仍将像以前一样将自身附加到全局对象(浏览器)上并正常运行。

文档挑战 (Documentation Challenges)

The last area that has been a challenge when building a new plugin is finding (or creating) vocabulary that allows you to talk about how these new concepts work and how others can benefit from these ideas in their projects. Over time, through talking with others, writing a specification, documentation, and many articles, this gap is being bridged, but any plugin dealing with a new technology or concept would face a similar communication gap at the outset.

构建新插件时遇到的最后一个挑战是查找(或创建)词汇表,该词汇表使您可以讨论这些新概念的工作原理以及其他人如何从他们的项目中受益。 随着时间的流逝,通过与其他人交谈,编写规范,文档和许多文章,这种差距正在弥合,但是任何涉及新技术或概念的插件一开始都会面临类似的沟通差距。

为什么要这样做? (Why Should You do the Same?)

After my experience building a plugin, I am more enthusiastic than ever about doing the same thing all over again! It feels like magic to do something you believed was impossible, and it’s very rewarding to experience the reaction of developers who are facing the same problems during the moment they realize how their problems can finally be solved.

在经历了构建插件的经验之后,我比以往任何时候都更加热衷于重新做同样的事情! 做您认为不可能的事情就像魔术一样,体验那些面临同样问题的开发人员在意识到自己的问题最终可以解决的那一刻,他们的React是非常有益的。

Sharing your solutions with the community is a win/win/win situation.

与社区共享您的解决方案是双赢/双赢的局面。

Everybody benefits from reading your code and using your techniques in their work

每个人都将从阅读您的代码和在工作中使用您的技术中受益 You benefit by having a standardized reference to start from in the future

您可以从将来获得标准化的参考中受益 Often other people will suggest features and report edge cases you have missed that help you improve your solution

通常,其他人会建议功能并报告您错过的重要案例,以帮助您改善解决方案

There’s no downside! Once you have a solution, if it’s a language feature like mine, you can move forward by writing a specification for the new feature and begin the process of proposing it to be included in the standard for that language.

没有缺点! 一旦有了解决方案,如果它是我的语言功能,则可以通过编写新功能的规范来向前发展,并开始提议将该功能包含在该语言的标准中。

Other things you can pursue once you have a plugin are ways of leveraging that solution as a way to research new ideas or concepts or using your plugin as a springboard for further plugin experiments. Since creating my plugin to solve my primary need for element queries, I’ve been able to use the increased power and flexibility of EQCSS to research and experiment CSS solutions in other areas as well. I’ve done experiments with things like aspect ratios (something CSS currently has no property for) and ways to extend the Attribute selector in CSS, plus plenty of other ideas.

有了插件后,您可以追求的其他事情是利用该解决方案作为研究新想法或新概念的方法,或者将插件用作进行进一步插件实验的跳板。 自从创建插件来解决我对元素查询的主要需求以来,我已经能够使用EQCSS增强的功能和灵活性来在其他领域研究和试验CSS解决方案。 我已经进行了宽高比 (CSS当前没有属性)和扩展CSS中的Attribute选择器的方法的实验,还有许多其他想法。

Out of these experiments, new plugins are being created, and hopefully they can also be leveraged to explore and discover even more ideas.

在这些实验中, 正在创建新的插件 ,希望它们也可以用于探索和发现更多的想法。

我唯一的遗憾 (My Only Regret)

After this transformative experience, the only thing that stings at all has been the realization that every feature we got functioning in the most cutting-edge browsers was something we also made work in IE8. That means in all of the years since IE8 was released it has been possible to do all of this, but until a couple of open-source developers collaborated and spent a few weeks building a plugin, it wasn’t being done.

在经历了这种变革性的体验之后,唯一让我感到震惊的是,人们意识到我们在最先进的浏览器中可以使用的每个功能都是我们也在IE8中完成的。 这意味着自IE8发行以来的所有年份中,已经可以完成所有这些工作 ,但是直到几个开源开发人员合作并花了几周的时间来构建插件之后,这项工作才得以实现。

If I have one regret about this entire process, it’s that the idea didn’t occur sooner! We could have been building websites this way for years already if somebody had taken the effort to create a plugin like this years ago.

如果我对整个过程感到后悔,那就是这个主意并没有很快出现! 如果有人像几年前一样努力创建一个插件,那么我们本可以以这种方式构建网站已经有很多年了。

期待 (Looking Forward)

So what does that mean for right now? What solutions are already possible today, and don’t require much work to realize, but simply don’t exist yet? If you have an idea about a solution for something, it makes sense to explore it and try building it sooner rather than later!

那么,这对现在意味着什么呢? 今天有什么解决方案已经可以实现 ,并且不需要很多工作来实现,但是根本不存在? 如果您对某事有解决方案的想法,则有必要对其进行探索并尽早构建而不是稍后构建!

My entire outlook on web development has changed after this experience, and it’s the kind of feeling that makes you jump out of bed in the morning feeling excited by the things you might create by the time you go to sleep that don’t currently exist right now.

在经历了这段经历之后,我对Web开发的整个看法发生了变化,这种感觉使您早晨起床,对入睡时可能创建的东西感到兴奋,这是当前不存在的。现在。

So I’ll ask you: What challenges do you face, and what ideas have you had about solving them?

因此,我将问您:您面临哪些挑战,您对解决这些挑战有什么想法?

翻译自: https://www.sitepoint.com/how-we-built-eqcss-why-you-should-try-building-your-own-polyfills-too/

相关资源:element-queries-spec:容器样式元素查询语法的规范-源码
最新回复(0)