{"tag":"scss","articles":{"blog\/technology\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome":{"key":"blog\/technology\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome","type":"article","published":true,"meta":{"createdAt":"2020-01-10T11:53:15+01:00","publishedAt":"2020-01-10T11:53:15+01:00","group":null,"links":[{"icon":"box-alt","colour":"primary","url":"https:\/\/packagist.org\/packages\/avris\/fontawesome-optimiser","displayUrl":"avris\/fontawesome-optimiser"}],"category":"blog","subcategory":"technology","slug":"reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome"},"content":{"en":{"slug":"reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome","title":"Reducing website size by a half by optimising Bootstrap and FontAwesome","intro":"\u003Cp\u003EMy new blog, despite being simple and freshly rewritten, loads way too much crap...\nSo I took a few moments to optimise it a bit \u2013 and I ended up with almost 50% reduction in resources size\nin just two steps!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cp\u003EMy new blog, despite being simple and freshly rewritten, loads way too much crap...\nSo I took a few moments to optimise it a bit \u2013 and I ended up with almost 50% reduction in resources size\nin just two steps!\u003C\/p\u003E\n\u003Ch3\u003EBootstrap\u003C\/h3\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/getbootstrap.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Bootstrap\u003C\/a\u003E is awesome. But it\u2019s also a lot.\nModals? Popovers? Tooltips? Badges? Toasts? I don\u2019t use any of that!\u003C\/p\u003E\n\u003Cp\u003EI already don\u2019t include any of Bootstrap\u2019s JavaScripts, but I should definitely clean up its CSS.\u003C\/p\u003E\n\u003Cp\u003ESo instead of including\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs scss border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\u0022\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EI went to its source and copy-pasted the modules that it was loading over there,\ncommenting out the ones I don\u2019t need:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs scss border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/functions\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/variables\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/mixins\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/root\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/reboot\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/type\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/images\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/code\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/grid\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/tables\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/forms\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/buttons\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/transitions\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/dropdown\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/button-group\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/input-group\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/custom-forms\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/nav\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/navbar\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/card\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/breadcrumb\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/pagination\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/badge\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/jumbotron\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/alert\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/progress\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/media\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/list-group\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/close\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/toasts\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/modal\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/tooltip\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/popover\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/carousel\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/spinners\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/utilities\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/print\u0022\u003C\/span\u003E;\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EThe only issue is that I do use \u003Ccode\u003Eforms.scss\u003C\/code\u003E \u003Cem\u003Ea bit\u003C\/em\u003E.\nThere is a search form in the header that has its \u003Ccode\u003E\u0026lt;input\u0026gt;\u003C\/code\u003E field styled.\u003C\/p\u003E\n\u003Cp\u003ESo I just inspected that element in Opera and pretty much just copy-pasted the three relevant selectors.\u003C\/p\u003E\n\u003Cp\u003EBum! Starting off with a minified CSS file of \u003Cstrong\u003E244 KB\u003C\/strong\u003E, now it\u2019s down to \u003Cstrong\u003E184 KB\u003C\/strong\u003E.\nA third of its weight is now gone.\u003C\/p\u003E\n\u003Cp\u003EBut that\u2019s just the first step.\u003C\/p\u003E\n\u003Ch3\u003EFontAwesome\u003C\/h3\u003E\n\u003Cp\u003EThe real big deal in terms of the website weight were the \u003Ca href=\u0022https:\/\/fontawesome.com\/icons\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E FontAwesome icons\u003C\/a\u003E.\nThere\u2019s thousands of icons included, but I only use a dozen \u2013 so why do I make visitors download them all?\u003C\/p\u003E\n\u003Cp\u003EYou can load FontAwesome in a number of different ways. One of them are \u003Ca href=\u0022https:\/\/fontawesome.com\/how-to-use\/on-the-web\/advanced\/svg-sprites\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E SVG sprites\u003C\/a\u003E.\nYou can include the definitions of the icons in a form of SVG \u003Ccode\u003E\u0026lt;symbols\u0026gt;\u003C\/code\u003Es, and whenever they\u2019re used,\njust use a \u003Ccode\u003E\u0026lt;use\u0026gt;\u003C\/code\u003E tag to reference it.\u003C\/p\u003E\n\u003Cp\u003ESo a wrote a simple service (plus a Twig extension) that would do exactly that:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eput \u003Ccode\u003E\u0026lt;use\u0026gt;\u003C\/code\u003E tags wherever an icon should be displayed,\u003C\/li\u003E\n\u003Cli\u003Ekeep track of the icons used,\u003C\/li\u003E\n\u003Cli\u003Edump the definions of the used icons at the bottom of the page.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EI just had to add some CSS to display the SVG icons the same way as webfonts\nin terms of size, position and using the color of the surrounding text:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs css border\u0022\u003E\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.icon\u003C\/span\u003E {\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E1.1em\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Eheight\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E1.1em\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Evertical-align\u003C\/span\u003E: -.\u003Cspan class=\u0022hljs-number\u0022\u003E125em\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Efill\u003C\/span\u003E: currentColor;\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EEt voil\u00e0!\nThe homepage of my blog went down from \u003Cstrong\u003E765 KB\u003C\/strong\u003E at the beginning,\nto \u003Cstrong\u003E704 KB\u003C\/strong\u003E after the first step, to \u003Cstrong\u003E393 KB\u003C\/strong\u003E now!\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-optimised_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u0022200\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB3UlEQVQ4ja2U227bMBBEz\/IiUqLapu7\/f2HdGEV0gcXL9kG24rQIkKKdF2KXFDU7M6CoqnKDqiIix3rvAeTrFR\/Cm\/3HFXh372\/OiKrq+XzGe0+tFRFBRGitATAMAwClFEophBDYtg2AruvIOWOMwTkHQG1KLYXWKiEGtuuGAjEEDqiCCKUqzgqX9SfBRr5++rwTmueZeZ4ppWCtJcbIuq6oKqqKMYZxTMzzjDZFb5OmYWBeFgRwzuG7jvPSMCI0bYgItTaitwA8BWG7PCPOA0o8nQ6OtTbGcURaa3qfvpQCgDHmUCWldFh3vV6JMZJzptZKjJFSCiKCtfbh8sq2bfR9T86Z1hrhQaHSFGfkqHPemKl8i+Ou0OVyYV3Xg1BKuxp368QYhr5nXVceMY4jLy8vdF1HrZUuDvyYC8YoqoIR0JtDQ2dJZMpN5fD0BdN1h4XWOVJKrwrdQ\/yvEHYSH+0fuJFyANM04b0\/rLqjtfZHb\/\/2NVsfoagoclQ7NQWaghHINeN9R+8cTkTw3jNPE7XtgYx9z7IsiEBrijWGISWmaXqjZEqJZVn2H4nQ9z3f54rIqyKlNoKziMApGrbnZzAGjDlC7a2n5oJE2TP0OPl779D\/eGMezxz6\/Vb\/AmBJWhxIiYZ2AAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-optimised_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u0022200\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EBtw, I\u2019ve put my little helper into \u003Ca href=\u0022https:\/\/packagist.org\/packages\/avris\/fontawesome-optimiser\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E a library\u003C\/a\u003E,\nif you want to check it out.\u003C\/p\u003E\n\u003Cp\u003EThere\u2019s caveats though...\nSVG is heavy. The two \u003Ccode\u003E.woff2\u003C\/code\u003E files I was using are \u003Cstrong\u003E261 KB\u003C\/strong\u003E overall,\nwhile the corresponding two sprites are \u003Cstrong\u003E2.1 MB\u003C\/strong\u003E.\nBut if I filter their content to just the icons I actually use (which is way simpler to do in SVG than in webfonts),\nit goes down to just \u003Cstrong\u003E44 KB\u003C\/strong\u003E!\nSo if your website is using a looot of fonts, you\u2019ll probably be better of generating a custom webfont.\u003C\/p\u003E\n\u003Cp\u003EThere can also be issues related to warm caches possibly circumventing the Optimiser,\nwith data that includes new icons being loaded dynamically in JS (which I don\u2019t do),\nwith the increased execution time (which doesn\u2019t bother me since I use an HTTP cache),\netc. Still, in many cases this trick can be very useful. Like mine.\u003C\/p\u003E\n\u003Cp\u003ESwitching from webfonts to dynamically filtered SVG sprites\nnot only removed the need for two requests \u003Ccode\u003E.woff2\u003C\/code\u003E files,\nbut also the need for the CSS that maps class names to font glyphs.\nMy CSS file went down again, from \u003Cstrong\u003E184 KB\u003C\/strong\u003E to just \u003Cstrong\u003E96 KB\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Ch3\u003ESumming up\u003C\/h3\u003E\n\u003Cp\u003ESo here I am: having spent not even a full evening on it, doing optimisations as simple as they can get,\nand ending up with the website trimmed of \u003Cstrong\u003Ehalf\u003C\/strong\u003E of its fat.\u003C\/p\u003E\n\u003Cp\u003ENice \ud83d\ude0e\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["website","web development","javascript","scss","css","bootstrap","fontawesome","svg","optimisation"],"hasMore":true,"image":null,"introLite":"\u003Cp\u003EMy new blog, despite being simple and freshly rewritten, loads way too much crap...\nSo I took a few moments to optimise it a bit \u2013 and I ended up with almost 50% reduction in resources size\nin just two steps!\u003C\/p\u003E","contentLite":"\u003Cp\u003EMy new blog, despite being simple and freshly rewritten, loads way too much crap...\nSo I took a few moments to optimise it a bit \u2013 and I ended up with almost 50% reduction in resources size\nin just two steps!\u003C\/p\u003E\n\u003Ch3\u003EBootstrap\u003C\/h3\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/getbootstrap.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Bootstrap\u003C\/a\u003E is awesome. But it\u2019s also a lot.\nModals? Popovers? Tooltips? Badges? Toasts? I don\u2019t use any of that!\u003C\/p\u003E\n\u003Cp\u003EI already don\u2019t include any of Bootstrap\u2019s JavaScripts, but I should definitely clean up its CSS.\u003C\/p\u003E\n\u003Cp\u003ESo instead of including\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-scss\u0022\u003E@import \u0022~bootstrap\u0022\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EI went to its source and copy-pasted the modules that it was loading over there,\ncommenting out the ones I don\u2019t need:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-scss\u0022\u003E@import \u0022~bootstrap\/scss\/functions\u0022;\n@import \u0022~bootstrap\/scss\/variables\u0022;\n@import \u0022~bootstrap\/scss\/mixins\u0022;\n@import \u0022~bootstrap\/scss\/root\u0022;\n@import \u0022~bootstrap\/scss\/reboot\u0022;\n@import \u0022~bootstrap\/scss\/type\u0022;\n\/\/@import \u0022~bootstrap\/scss\/images\u0022;\n@import \u0022~bootstrap\/scss\/code\u0022;\n@import \u0022~bootstrap\/scss\/grid\u0022;\n@import \u0022~bootstrap\/scss\/tables\u0022;\n\/\/@import \u0022~bootstrap\/scss\/forms\u0022;\n@import \u0022~bootstrap\/scss\/buttons\u0022;\n\/\/@import \u0022~bootstrap\/scss\/transitions\u0022;\n\/\/@import \u0022~bootstrap\/scss\/dropdown\u0022;\n@import \u0022~bootstrap\/scss\/button-group\u0022;\n@import \u0022~bootstrap\/scss\/input-group\u0022;\n\/\/@import \u0022~bootstrap\/scss\/custom-forms\u0022;\n\/\/@import \u0022~bootstrap\/scss\/nav\u0022;\n\/\/@import \u0022~bootstrap\/scss\/navbar\u0022;\n@import \u0022~bootstrap\/scss\/card\u0022;\n\/\/@import \u0022~bootstrap\/scss\/breadcrumb\u0022;\n\/\/@import \u0022~bootstrap\/scss\/pagination\u0022;\n\/\/@import \u0022~bootstrap\/scss\/badge\u0022;\n\/\/@import \u0022~bootstrap\/scss\/jumbotron\u0022;\n@import \u0022~bootstrap\/scss\/alert\u0022;\n\/\/@import \u0022~bootstrap\/scss\/progress\u0022;\n\/\/@import \u0022~bootstrap\/scss\/media\u0022;\n\/\/@import \u0022~bootstrap\/scss\/list-group\u0022;\n\/\/@import \u0022~bootstrap\/scss\/close\u0022;\n\/\/@import \u0022~bootstrap\/scss\/toasts\u0022;\n\/\/@import \u0022~bootstrap\/scss\/modal\u0022;\n\/\/@import \u0022~bootstrap\/scss\/tooltip\u0022;\n\/\/@import \u0022~bootstrap\/scss\/popover\u0022;\n\/\/@import \u0022~bootstrap\/scss\/carousel\u0022;\n\/\/@import \u0022~bootstrap\/scss\/spinners\u0022;\n@import \u0022~bootstrap\/scss\/utilities\u0022;\n@import \u0022~bootstrap\/scss\/print\u0022;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EThe only issue is that I do use \u003Ccode\u003Eforms.scss\u003C\/code\u003E \u003Cem\u003Ea bit\u003C\/em\u003E.\nThere is a search form in the header that has its \u003Ccode\u003E\u0026lt;input\u0026gt;\u003C\/code\u003E field styled.\u003C\/p\u003E\n\u003Cp\u003ESo I just inspected that element in Opera and pretty much just copy-pasted the three relevant selectors.\u003C\/p\u003E\n\u003Cp\u003EBum! Starting off with a minified CSS file of \u003Cstrong\u003E244 KB\u003C\/strong\u003E, now it\u2019s down to \u003Cstrong\u003E184 KB\u003C\/strong\u003E.\nA third of its weight is now gone.\u003C\/p\u003E\n\u003Cp\u003EBut that\u2019s just the first step.\u003C\/p\u003E\n\u003Ch3\u003EFontAwesome\u003C\/h3\u003E\n\u003Cp\u003EThe real big deal in terms of the website weight were the \u003Ca href=\u0022https:\/\/fontawesome.com\/icons\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E FontAwesome icons\u003C\/a\u003E.\nThere\u2019s thousands of icons included, but I only use a dozen \u2013 so why do I make visitors download them all?\u003C\/p\u003E\n\u003Cp\u003EYou can load FontAwesome in a number of different ways. One of them are \u003Ca href=\u0022https:\/\/fontawesome.com\/how-to-use\/on-the-web\/advanced\/svg-sprites\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E SVG sprites\u003C\/a\u003E.\nYou can include the definitions of the icons in a form of SVG \u003Ccode\u003E\u0026lt;symbols\u0026gt;\u003C\/code\u003Es, and whenever they\u2019re used,\njust use a \u003Ccode\u003E\u0026lt;use\u0026gt;\u003C\/code\u003E tag to reference it.\u003C\/p\u003E\n\u003Cp\u003ESo a wrote a simple service (plus a Twig extension) that would do exactly that:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eput \u003Ccode\u003E\u0026lt;use\u0026gt;\u003C\/code\u003E tags wherever an icon should be displayed,\u003C\/li\u003E\n\u003Cli\u003Ekeep track of the icons used,\u003C\/li\u003E\n\u003Cli\u003Edump the definions of the used icons at the bottom of the page.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EI just had to add some CSS to display the SVG icons the same way as webfonts\nin terms of size, position and using the color of the surrounding text:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-css\u0022\u003E.icon {\n    width: 1.1em;\n    height: 1.1em;\n    vertical-align: -.125em;\n    fill: currentColor;\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EEt voil\u00e0!\nThe homepage of my blog went down from \u003Cstrong\u003E765 KB\u003C\/strong\u003E at the beginning,\nto \u003Cstrong\u003E704 KB\u003C\/strong\u003E after the first step, to \u003Cstrong\u003E393 KB\u003C\/strong\u003E now!\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-optimised_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-optimised_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u002260\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EBtw, I\u2019ve put my little helper into \u003Ca href=\u0022https:\/\/packagist.org\/packages\/avris\/fontawesome-optimiser\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E a library\u003C\/a\u003E,\nif you want to check it out.\u003C\/p\u003E\n\u003Cp\u003EThere\u2019s caveats though...\nSVG is heavy. The two \u003Ccode\u003E.woff2\u003C\/code\u003E files I was using are \u003Cstrong\u003E261 KB\u003C\/strong\u003E overall,\nwhile the corresponding two sprites are \u003Cstrong\u003E2.1 MB\u003C\/strong\u003E.\nBut if I filter their content to just the icons I actually use (which is way simpler to do in SVG than in webfonts),\nit goes down to just \u003Cstrong\u003E44 KB\u003C\/strong\u003E!\nSo if your website is using a looot of fonts, you\u2019ll probably be better of generating a custom webfont.\u003C\/p\u003E\n\u003Cp\u003EThere can also be issues related to warm caches possibly circumventing the Optimiser,\nwith data that includes new icons being loaded dynamically in JS (which I don\u2019t do),\nwith the increased execution time (which doesn\u2019t bother me since I use an HTTP cache),\netc. Still, in many cases this trick can be very useful. Like mine.\u003C\/p\u003E\n\u003Cp\u003ESwitching from webfonts to dynamically filtered SVG sprites\nnot only removed the need for two requests \u003Ccode\u003E.woff2\u003C\/code\u003E files,\nbut also the need for the CSS that maps class names to font glyphs.\nMy CSS file went down again, from \u003Cstrong\u003E184 KB\u003C\/strong\u003E to just \u003Cstrong\u003E96 KB\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Ch3\u003ESumming up\u003C\/h3\u003E\n\u003Cp\u003ESo here I am: having spent not even a full evening on it, doing optimisations as simple as they can get,\nand ending up with the website trimmed of \u003Cstrong\u003Ehalf\u003C\/strong\u003E of its fat.\u003C\/p\u003E\n\u003Cp\u003ENice \ud83d\ude0e\u003C\/p\u003E","words":752,"readTime":4,"lang":"en"}}},"blog\/technology\/frontendowa-magia-coffeescript-sass-scss-less":{"key":"blog\/technology\/frontendowa-magia-coffeescript-sass-scss-less","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:39+02:00","publishedAt":"2015-07-26T18:00:00+02:00","group":null,"category":"blog","subcategory":"technology","slug":"frontendowa-magia-coffeescript-sass-scss-less"},"content":{"pl":{"slug":"frontendowa-magia-coffeescript-sass-scss-less","title":"Frontendowa magia: CoffeeScript, Sass, Scss, Less...","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_small.jpeg\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022364.93358633776\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEuUlEQVRIib2X228UVRzHP2dmdna6l962l+XSLaVeSiFRsoqAQf8A4jvvtn+CzxhjMDHEEJ8MATG+mfiAzz4QTYCk4UExpqlgAxTa0la67exlZs6Zc3woW7f2tqvQbzKZ35mcM9\/f\/M739zu\/EWYNCCEAeNF24x3Y1XbqgzqasVtBfV2zHEJrbf4T0\/9EHMfYtr3pubUX5I1RmJmZ4fz5j7l27ZstI+XshUMAs7OzXLlyFSkl4+NjFAqFLecJU1fVS8Lc3BxXr36N75cZHx9jePjwjnp04MVnFkAQhFy\/\/gMTExOMjX3IkSMjwO5ZJnZK+0YYY4iiiLt37zI7OwcYOju7KBQGKBQK2LaNMQalFE+ezJNwXNLpBK7IYrcLXGEgjhBOeneHmgn9rVu3uXDhM0ql0iZH29raOHbsKMVikePH3ySVSjM0mAMrBWYZVbZY8Vbokg6iEiN6D227bU05pJTi7NkPKJfL68+klERRhDEGy7LWvzCOY3K5borFtzh9+hT9\/XkqlSqO7XDmVDtOIgdEiMQrW3I1nWWWZaG1BkBrTalUeu6QXp+TzXTQ6e0jWx1m9qcuFjs93jlxiGx7llSqjcjSPFA1hkyJ2oIi27eZ3mlmx2zb5uLFz7l06UsmJycRQtDb04sKLOywg5Q8QF\/yCKP73yVccZl\/sohlWaQqefYfyD8P6W\/UghKHvbexsMj0\/qNZaDg6Gs+b+oSt7NHRUS5f\/gqlFN99Osn33\/6IKttYsUfSypJO99A3fJggMkROBks4xKXnOtGr4Izgq18IHldJWR6dA1vX5JYKoxACx3F4FP9M3D2DlejAjjpxSZPJpsn1SGqpgIXgKWX3EU9H7qH0R6hVDy9zn1wiT2ZgGUT\/thybHNrtEDTGML8yTdw3jek1aNsmSCYptbcz90aRimXxV\/sd0rJGWBrCSIfrn\/zOuQuDlJNZMiIAvA3vbZSNVR8YYzZcWhvi2KCkRkYxUaSIIoXvV\/F9H8dx8DyPTDpJPpsi\/16ITC2TTdfYl1OcyXl4lWc48R3OfTGCuXmbvNE0Hp91rrq9ZYSUNIRhRBRJtNYNixQA0\/P3OJD3KZVsnESCXDeUqwZvKUk50iS7F1gopZnKr5B41oHiVRL6GeL9AbAkQng7FsYNyooVVKsB1WoNKSVKqbUrjpEKypFBrUimpta+I5N1kbEAI9jnS9yMICocxdiaP2faSNYqzC8\/xjcGnNeB5LbaWd+yDQN7LcUNawVOKbVWAMOQMAjQQY3FJR+tfQouHHutzGrJxvb7mZrzWFgKcVYWsJTg6KjDH0nwoxhLJP9NtS02pL0QkM64uK5NtRYS1AKiKEJrjZQRYRixtLRIqEC6gpsT4NiSnqEHtLkpDvqrTP+6xODBVe7dt6jVPGLfJm11NuUMNBTGRqUnXJsON0V7ewqtDTrWxDrGX\/VRShFrxcOqJpFIEAt4vAqOlswlKqQti1AKyhWDMWvb3YhGnq3slvshKRU3btxgYmKChw8fsby8TDZrcGybMEriukm6uroYHBzk5MkTFIvFDeu36yTWe+8X0VMHQUAcxziOQzK5u3B3wp40+a38Bu1Jk98KWnao8T+rGbtlh142Qav4G4sUzOeqTN6uAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_small.jpeg\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022364.93358633776\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022729.86717267552\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEuUlEQVRIib2X228UVRzHP2dmdna6l962l+XSLaVeSiFRsoqAQf8A4jvvtn+CzxhjMDHEEJ8MATG+mfiAzz4QTYCk4UExpqlgAxTa0la67exlZs6Zc3woW7f2tqvQbzKZ35mcM9\/f\/M739zu\/EWYNCCEAeNF24x3Y1XbqgzqasVtBfV2zHEJrbf4T0\/9EHMfYtr3pubUX5I1RmJmZ4fz5j7l27ZstI+XshUMAs7OzXLlyFSkl4+NjFAqFLecJU1fVS8Lc3BxXr36N75cZHx9jePjwjnp04MVnFkAQhFy\/\/gMTExOMjX3IkSMjwO5ZJnZK+0YYY4iiiLt37zI7OwcYOju7KBQGKBQK2LaNMQalFE+ezJNwXNLpBK7IYrcLXGEgjhBOeneHmgn9rVu3uXDhM0ql0iZH29raOHbsKMVikePH3ySVSjM0mAMrBWYZVbZY8Vbokg6iEiN6D227bU05pJTi7NkPKJfL68+klERRhDEGy7LWvzCOY3K5borFtzh9+hT9\/XkqlSqO7XDmVDtOIgdEiMQrW3I1nWWWZaG1BkBrTalUeu6QXp+TzXTQ6e0jWx1m9qcuFjs93jlxiGx7llSqjcjSPFA1hkyJ2oIi27eZ3mlmx2zb5uLFz7l06UsmJycRQtDb04sKLOywg5Q8QF\/yCKP73yVccZl\/sohlWaQqefYfyD8P6W\/UghKHvbexsMj0\/qNZaDg6Gs+b+oSt7NHRUS5f\/gqlFN99Osn33\/6IKttYsUfSypJO99A3fJggMkROBks4xKXnOtGr4Izgq18IHldJWR6dA1vX5JYKoxACx3F4FP9M3D2DlejAjjpxSZPJpsn1SGqpgIXgKWX3EU9H7qH0R6hVDy9zn1wiT2ZgGUT\/thybHNrtEDTGML8yTdw3jek1aNsmSCYptbcz90aRimXxV\/sd0rJGWBrCSIfrn\/zOuQuDlJNZMiIAvA3vbZSNVR8YYzZcWhvi2KCkRkYxUaSIIoXvV\/F9H8dx8DyPTDpJPpsi\/16ITC2TTdfYl1OcyXl4lWc48R3OfTGCuXmbvNE0Hp91rrq9ZYSUNIRhRBRJtNYNixQA0\/P3OJD3KZVsnESCXDeUqwZvKUk50iS7F1gopZnKr5B41oHiVRL6GeL9AbAkQng7FsYNyooVVKsB1WoNKSVKqbUrjpEKypFBrUimpta+I5N1kbEAI9jnS9yMICocxdiaP2faSNYqzC8\/xjcGnNeB5LbaWd+yDQN7LcUNawVOKbVWAMOQMAjQQY3FJR+tfQouHHutzGrJxvb7mZrzWFgKcVYWsJTg6KjDH0nwoxhLJP9NtS02pL0QkM64uK5NtRYS1AKiKEJrjZQRYRixtLRIqEC6gpsT4NiSnqEHtLkpDvqrTP+6xODBVe7dt6jVPGLfJm11NuUMNBTGRqUnXJsON0V7ewqtDTrWxDrGX\/VRShFrxcOqJpFIEAt4vAqOlswlKqQti1AKyhWDMWvb3YhGnq3slvshKRU3btxgYmKChw8fsby8TDZrcGybMEriukm6uroYHBzk5MkTFIvFDeu36yTWe+8X0VMHQUAcxziOQzK5u3B3wp40+a38Bu1Jk98KWnao8T+rGbtlh142Qav4G4sUzOeqTN6uAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022729.86717267552\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E\n\u003Cp\u003EZ drugiej jednak strony t\u0119 sam\u0105 przeno\u015bno\u015b\u0107 mo\u017cna te\u017c uzna\u0107 za wad\u0119. Ca\u0142y Internet sprowadza si\u0119 bowiem ostatnio do tej \u015bwi\u0119tej tr\u00f3jcy: \u003Cstrong\u003EHTML5 + CSS3 + JS\u003C\/strong\u003E. Bo skoro te trzy potrafi\u0105 ju\u017c wszystko to, co kiedy\u015b umia\u0142y tylko \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/flash\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Flash\u003C\/a\u003E czy aplety \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/java\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Javy\u003C\/a\u003E, to po co ryzykowa\u0107 bezpiecze\u0144stwo witryny, zmusza\u0107 u\u017cytkownika do instalowania wtyczek i odbiera\u0107 sobie mo\u017cliwo\u015b\u0107 lepszej integracji element\u00f3w strony? Po prostu \u003Cem\u003Enie ma sensu\u003C\/em\u003E wychodzi\u0107 poza \u015bwi\u0119t\u0105 tr\u00f3jc\u0119. A jej rozw\u00f3j jest niestety ograniczony aktualizacjami przegl\u0105darek. Czy zatem jeste\u015bmy na ni\u0105 \u003Cstrong\u003Eskazani\u003C\/strong\u003E?\u003C\/p\u003E\n\u003Cp\u003ENa szcz\u0119\u015bcie nie! Istnieje ca\u0142a rodzina j\u0119zyk\u00f3w, kt\u00f3re bardzo sprytnie obchodz\u0105 ten problem. Wprowadzaj\u0105 ogromne ulepszenia i u\u0142atwienia, ale bez potrzeby interpretowania ich przez przegl\u0105darki! Po prostu po stronie programisty s\u0105 kompilowane do jednego z tych j\u0119zyk\u00f3w, kt\u00f3re ka\u017cda przegl\u0105darka rozumie.\u003C\/p\u003E\n\u003Cp\u003EPowiedzmy na przyk\u0142ad, \u017ce chcesz stworzy\u0107 w CSS klasy od \u003Ccode\u003Ecol-1\u003C\/code\u003E do \u003Ccode\u003Ecol-12\u003C\/code\u003E, z kt\u00f3rych ka\u017cda b\u0119dzie nadawa\u0142a DIV-owi szeroko\u015b\u0107 r\u00f3wn\u0105 ile\u015btam dwunastych szeroko\u015bci kontenera. W \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/thesassway.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Sass\u003C\/a\u003E\u003C\/strong\u003E zajmuje to trzy linijki:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs scss border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003E@for\u003C\/span\u003E \u003Cspan class=\u0022hljs-variable\u0022\u003E$i\u003C\/span\u003E from \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E through \u003Cspan class=\u0022hljs-number\u0022\u003E12\u003C\/span\u003E\n  .col-#{\u003Cspan class=\u0022hljs-variable\u0022\u003E$i\u003C\/span\u003E}\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-variable\u0022\u003E$i\u003C\/span\u003E\/\u003Cspan class=\u0022hljs-number\u0022\u003E12\u003C\/span\u003E * \u003Cspan class=\u0022hljs-number\u0022\u003E100%\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EA jest kompilowane do takiego kodu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs css border\u0022\u003E\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-1\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E8.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-2\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E16.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-3\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E25%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-4\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E33.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-5\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E41.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-6\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E50%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-7\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E58.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-8\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E66.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-9\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E75%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-10\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E83.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-11\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E91.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-12\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E100%\u003C\/span\u003E; }\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EPierwszy z nich jest prosty, kr\u00f3tki i czytelny dla cz\u0142owieka, drugi natomiast zostanie zrozumiany przez wszystkie przegl\u0105darki. I wilk syty i owca ca\u0142a! Sass zawiera wiele element\u00f3w, kt\u00f3rych prostemu CSS-owi brakuje: zmiennych, instrukcji warunkowych, p\u0119tli, funkcji (tzw. mixins), zagnie\u017cd\u017ce\u0144, operacji arytmetycznych... O ile bardziej \u003Cstrong\u003Eelastyczny\u003C\/strong\u003E staje si\u0119 kod, gdy mo\u017cemy zdefiniowa\u0107 na przyk\u0142ad zmienn\u0105 \u003Ccode\u003E$navWidth: 300px\u003C\/code\u003E i u\u017cy\u0107 jej w pi\u0119ciu innych miejscach (r\u00f3wnie\u017c w wyra\u017ceniach arytmetycznych, np. \u003Ccode\u003Ewidth: $navWidth \/ 2 + 16px\u003C\/code\u003E), zamiast wsz\u0119dzie podawa\u0107 j\u0105 wprost. Ka\u017cda zmiana szeroko\u015bci nawigacji jest wtedy po prostu \u003Cstrong\u003Ebanalna\u003C\/strong\u003E, nie wymaga szukania wszystkich zale\u017cno\u015bci. O ile \u003Cstrong\u003Ekr\u00f3tszy i bardziej przejrzysty\u003C\/strong\u003E staje si\u0119 kod, je\u015bli mo\u017cemy cz\u0119sto powtarzaj\u0105ce si\u0119 elementy zamkn\u0105\u0107 w parametryzowane mixiny i po prostu si\u0119 do nich odwo\u0142ywa\u0107? \u015awietn\u0105 list\u0119 sassowych ficzer\u00f3w mo\u017cna znale\u017a\u0107 cho\u0107by na \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Sass_(stylesheet_language)\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Wikipedii\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cp\u003EPodobnymi do niego j\u0119zykami s\u0105 \u003Cstrong\u003EScss\u003C\/strong\u003E oras \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/lesscss.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Less\u003C\/a\u003E\u003C\/strong\u003E. Wol\u0119 jednak Sassa z jednego powodu \u2013 \u003Cstrong\u003Ebrak klamer\u003C\/strong\u003E. Skoro i tak w ka\u017cdym kodzie powinno si\u0119 stosowa\u0107 odpowiednie wci\u0119cia tabulatorami, to klamry staj\u0105 si\u0119 zwyczajnie zb\u0119dne. J\u0119zyk, kt\u00f3ry wymusza stosowanie wci\u0119\u0107 w kodzie po pierwsze wymaga mniej klepania w klawiatur\u0119, a po drugie daje gwarancj\u0119, \u017ce po kim by\u015bmy kodu nie przej\u0119li, zawsze przynajmniej pod tym wzgl\u0119dem b\u0119dzie on czytelny. Same plusy! Z tego samego za\u0142o\u017cenia wyszli chocia\u017cby tw\u00f3rcy \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.ruby-lang.org\/pl\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Rubiego\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.python.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Pythona\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E CoffeeScriptu\u003C\/a\u003E\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Cp\u003EA no w\u0142a\u015bnie, \u003Cstrong\u003ECoffeeScript\u003C\/strong\u003E. \u017bywy dow\u00f3d, \u017ce nawet tworzenie JavaScript\u00f3w mo\u017ce by\u0107 przyjemne (s\u0142owo daj\u0119, nie uwierzy\u0142bym, gdybym nie spr\u00f3bowa\u0142). W JS to dopiero jest nadmiar nawias\u00f3w i klamer:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Esse = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E EventSource(Routing.generate(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_check\u0027\u003C\/span\u003E));\nsse.addEventListener(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Ee\u003C\/span\u003E) \u003C\/span\u003E{\n  \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (e.data == \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027test\u0027\u003C\/span\u003E || e.data == \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dev\u0027\u003C\/span\u003E) { \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E; }\n  $.post(Routing.generate(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_fetch\u0027\u003C\/span\u003E), { \u003Cspan class=\u0022hljs-attr\u0022\u003Eids\u003C\/span\u003E: e.data }, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Edata\u003C\/span\u003E) \u003C\/span\u003E{\n    conversation.html(data);\n  });\n}, \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E);\n\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETa sama funkcjonalno\u015b\u0107 w CoffeeScripcie wygl\u0105da nast\u0119puj\u0105co:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Esse = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E EventSource Routing.generate \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_check\u0027\u003C\/span\u003E\nsse.addEventListener \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation\u0027\u003C\/span\u003E, (e) -\u0026gt;\n  \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E e.data \u003Cspan class=\u0022hljs-keyword\u0022\u003Ein\u003C\/span\u003E [\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027test\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dev\u0027\u003C\/span\u003E]\n  $.post(Routing.generate(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_fetch\u0027\u003C\/span\u003E), { \u003Cspan class=\u0022hljs-attr\u0022\u003Eids\u003C\/span\u003E: e.data }, (data) -\u0026gt;\n    conversation.html(data)\n  )\n, \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWystarczy\u0142o zast\u0105pienie sk\u0142adni \u003Ccode\u003Efunction(a) {...}\u003C\/code\u003E prostym \u003Ccode\u003E(a) -\u0026gt; ...\u003C\/code\u003E, zmiana klamer na wci\u0119cia oraz mo\u017cliwo\u015b\u0107 pomini\u0119cia niekt\u00f3rych nawias\u00f3w w parametrach funkcji \u2013 i voil\u00e0! Mniej klepania w klawiatur\u0119 i doszukiwania si\u0119 par nawias\u00f3w, a tre\u015bci tyle samo!\u003C\/p\u003E\n\u003Cp\u003ENie spos\u00f3b si\u0119 nachwali\u0107 wszystkich ficzer\u00f3w CoffeeScriptu... JSON-owe obiekty mo\u017cna w nim definiowa\u0107 podobnie jak w \u003Ca href=\u0022http:\/\/yaml.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E YAML-u\u003C\/a\u003E, p\u0119tl\u0119 mo\u017cna od 1 do 100 zawrze\u0107 w kr\u00f3ciutkim zapisie \u003Ccode\u003E1..100\u003C\/code\u003E, zmiennych nie trzeba deklarowa\u0107, mo\u017cna im przypisywa\u0107 warto\u015bci do wielu na raz (a nawet zamienia\u0107 je warto\u015bciami w jednej linijce: \u003Ccode\u003E[foo, bar] = [bar, foo]\u003C\/code\u003E i tyle!). Najlepiej po prostu przejrze\u0107 jego \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E stron\u0119 domow\u0105\u003C\/a\u003E i milcze\u0107 w \u003Cstrong\u003Ezachwycie\u003C\/strong\u003E!\u003C\/p\u003E\n\u003Cp\u003ER\u00f3wnie\u017c w przypadku HTML-a istnieje wiele technologii, kt\u00f3re pozwalaj\u0105 na wygenerowanie go na postawie bardziej wyrafinowanych j\u0119zyk\u00f3w. Lecz tutaj to troch\u0119 co innego. Mowa o template engines takich jak \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/twig.sensiolabs.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Twig\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.smarty.net\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Smarty\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/haml.info\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Haml\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.stuartellis.eu\/articles\/erb\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Erb\u003C\/a\u003E\u003C\/strong\u003E \u2013 one jednak s\u0105 kompilowane do j\u0119zyk\u00f3w wykonywanych po stronie serwera (PHP, Ruby, Python...), wi\u0119c niezbyt pasuj\u0105 do mojego zestawienia. (Nota bene w Hamlu jeszcze bardziej zredukowana jest klamrowa redundancja: z \u003Ccode\u003E\u0026lt;html\u0026gt;\u0026lt;\/html\u0026gt;\u003C\/code\u003E robi si\u0119 zwyk\u0142e \u003Ccode\u003E%html\u003C\/code\u003E)\u003C\/p\u003E\n\u003Cp\u003EPotrafi\u0119 znale\u017a\u0107 tylko dwie wady ca\u0142ej tej rodziny technologii w por\u00f3wnaniu do \u003Cem\u003E\u015bwi\u0119tej tr\u00f3jcy\u003C\/em\u003E. Po pierwsze, tak jak przegl\u0105darki, tak samo frontendowi programi\u015bci tr\u00f3jc\u0119 znaj\u0105 z ca\u0142\u0105 pewno\u015bci\u0105, czego nie zawsze mo\u017cna powiedzie\u0107 o jej m\u0142odszym rodze\u0144stwie. Wi\u0119c je\u015bli kto\u015b dostanie po tobie projekt, w kt\u00f3rym u\u017cywa\u0142e\u015b Sassa czy CoffeeScriptu, mo\u017ce nie by\u0107 mu zbyt kolorowo. Z drugiej jednak strony, s\u0105 to przecie\u017c technologie \u003Cstrong\u003Ebardzo \u0142atwe do przyswojenia\u003C\/strong\u003E, a zarazem niezmiernie przydatne i wygodne. Wi\u0119c chyba tylko wy\u015bwiadczy\u0142by\u015b mu przys\u0142ug\u0119, prawda?\u003C\/p\u003E\n\u003Cp\u003EPo drugie natomiast, kompilowanie trwa i wymaga zachodu. Wystarczy jednak zainstalowa\u0107 \u003Ca href=\u0022http:\/\/bower.io\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Bowera\u003C\/a\u003E albo skonfigurowa\u0107 sobie watchera w \u003Ca href=\u0022https:\/\/www.jetbrains.com\/phpstorm\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E PhpStormie\u003C\/a\u003E, aby ka\u017cde zapisanie pliku automatycznie uruchamia\u0142o kompilacj\u0119. Naprawd\u0119, wygodniej ju\u017c si\u0119 tego zrobi\u0107 nie da!\u003C\/p\u003E\n\u003Cp\u003EA poza tym \u003Cstrong\u003Esame plusy\u003C\/strong\u003E. Je\u015bli tworzysz strony, a jeszcze nie znasz tych technologii \u2013 \u003Cstrong\u003Ekoniecznie je wypr\u00f3buj!\u003C\/strong\u003E Z odrobin\u0105 wprawy i do\u015bwiadczenia, po\u0142owa twoich frontendowych problem\u00f3w mo\u017ce znikn\u0105\u0107.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["coffeescript","frontend","haml","html","internet","javascript","kompilacja","less","programowanie","sass","scss","twig"],"hasMore":true,"image":"https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_small.jpeg","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_mini.jpeg\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022182.46679316888\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_mini.jpeg\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022182.46679316888\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E\n\u003Cp\u003EZ drugiej jednak strony t\u0119 sam\u0105 przeno\u015bno\u015b\u0107 mo\u017cna te\u017c uzna\u0107 za wad\u0119. Ca\u0142y Internet sprowadza si\u0119 bowiem ostatnio do tej \u015bwi\u0119tej tr\u00f3jcy: \u003Cstrong\u003EHTML5 + CSS3 + JS\u003C\/strong\u003E. Bo skoro te trzy potrafi\u0105 ju\u017c wszystko to, co kiedy\u015b umia\u0142y tylko \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/flash\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Flash\u003C\/a\u003E czy aplety \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/java\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Javy\u003C\/a\u003E, to po co ryzykowa\u0107 bezpiecze\u0144stwo witryny, zmusza\u0107 u\u017cytkownika do instalowania wtyczek i odbiera\u0107 sobie mo\u017cliwo\u015b\u0107 lepszej integracji element\u00f3w strony? Po prostu \u003Cem\u003Enie ma sensu\u003C\/em\u003E wychodzi\u0107 poza \u015bwi\u0119t\u0105 tr\u00f3jc\u0119. A jej rozw\u00f3j jest niestety ograniczony aktualizacjami przegl\u0105darek. Czy zatem jeste\u015bmy na ni\u0105 \u003Cstrong\u003Eskazani\u003C\/strong\u003E?\u003C\/p\u003E\n\u003Cp\u003ENa szcz\u0119\u015bcie nie! Istnieje ca\u0142a rodzina j\u0119zyk\u00f3w, kt\u00f3re bardzo sprytnie obchodz\u0105 ten problem. Wprowadzaj\u0105 ogromne ulepszenia i u\u0142atwienia, ale bez potrzeby interpretowania ich przez przegl\u0105darki! Po prostu po stronie programisty s\u0105 kompilowane do jednego z tych j\u0119zyk\u00f3w, kt\u00f3re ka\u017cda przegl\u0105darka rozumie.\u003C\/p\u003E\n\u003Cp\u003EPowiedzmy na przyk\u0142ad, \u017ce chcesz stworzy\u0107 w CSS klasy od \u003Ccode\u003Ecol-1\u003C\/code\u003E do \u003Ccode\u003Ecol-12\u003C\/code\u003E, z kt\u00f3rych ka\u017cda b\u0119dzie nadawa\u0142a DIV-owi szeroko\u015b\u0107 r\u00f3wn\u0105 ile\u015btam dwunastych szeroko\u015bci kontenera. W \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/thesassway.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Sass\u003C\/a\u003E\u003C\/strong\u003E zajmuje to trzy linijki:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E@for $i from 1 through 12\n  .col-#{$i}\n    width: $i\/12 * 100%\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EA jest kompilowane do takiego kodu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E.col-1 {\n  width: 8.33333%; }\n\n.col-2 {\n  width: 16.66667%; }\n\n.col-3 {\n  width: 25%; }\n\n.col-4 {\n  width: 33.33333%; }\n\n.col-5 {\n  width: 41.66667%; }\n\n.col-6 {\n  width: 50%; }\n\n.col-7 {\n  width: 58.33333%; }\n\n.col-8 {\n  width: 66.66667%; }\n\n.col-9 {\n  width: 75%; }\n\n.col-10 {\n  width: 83.33333%; }\n\n.col-11 {\n  width: 91.66667%; }\n\n.col-12 {\n  width: 100%; }\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EPierwszy z nich jest prosty, kr\u00f3tki i czytelny dla cz\u0142owieka, drugi natomiast zostanie zrozumiany przez wszystkie przegl\u0105darki. I wilk syty i owca ca\u0142a! Sass zawiera wiele element\u00f3w, kt\u00f3rych prostemu CSS-owi brakuje: zmiennych, instrukcji warunkowych, p\u0119tli, funkcji (tzw. mixins), zagnie\u017cd\u017ce\u0144, operacji arytmetycznych... O ile bardziej \u003Cstrong\u003Eelastyczny\u003C\/strong\u003E staje si\u0119 kod, gdy mo\u017cemy zdefiniowa\u0107 na przyk\u0142ad zmienn\u0105 \u003Ccode\u003E$navWidth: 300px\u003C\/code\u003E i u\u017cy\u0107 jej w pi\u0119ciu innych miejscach (r\u00f3wnie\u017c w wyra\u017ceniach arytmetycznych, np. \u003Ccode\u003Ewidth: $navWidth \/ 2 + 16px\u003C\/code\u003E), zamiast wsz\u0119dzie podawa\u0107 j\u0105 wprost. Ka\u017cda zmiana szeroko\u015bci nawigacji jest wtedy po prostu \u003Cstrong\u003Ebanalna\u003C\/strong\u003E, nie wymaga szukania wszystkich zale\u017cno\u015bci. O ile \u003Cstrong\u003Ekr\u00f3tszy i bardziej przejrzysty\u003C\/strong\u003E staje si\u0119 kod, je\u015bli mo\u017cemy cz\u0119sto powtarzaj\u0105ce si\u0119 elementy zamkn\u0105\u0107 w parametryzowane mixiny i po prostu si\u0119 do nich odwo\u0142ywa\u0107? \u015awietn\u0105 list\u0119 sassowych ficzer\u00f3w mo\u017cna znale\u017a\u0107 cho\u0107by na \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Sass_(stylesheet_language)\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Wikipedii\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cp\u003EPodobnymi do niego j\u0119zykami s\u0105 \u003Cstrong\u003EScss\u003C\/strong\u003E oras \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/lesscss.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Less\u003C\/a\u003E\u003C\/strong\u003E. Wol\u0119 jednak Sassa z jednego powodu \u2013 \u003Cstrong\u003Ebrak klamer\u003C\/strong\u003E. Skoro i tak w ka\u017cdym kodzie powinno si\u0119 stosowa\u0107 odpowiednie wci\u0119cia tabulatorami, to klamry staj\u0105 si\u0119 zwyczajnie zb\u0119dne. J\u0119zyk, kt\u00f3ry wymusza stosowanie wci\u0119\u0107 w kodzie po pierwsze wymaga mniej klepania w klawiatur\u0119, a po drugie daje gwarancj\u0119, \u017ce po kim by\u015bmy kodu nie przej\u0119li, zawsze przynajmniej pod tym wzgl\u0119dem b\u0119dzie on czytelny. Same plusy! Z tego samego za\u0142o\u017cenia wyszli chocia\u017cby tw\u00f3rcy \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.ruby-lang.org\/pl\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Rubiego\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.python.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Pythona\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E CoffeeScriptu\u003C\/a\u003E\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Cp\u003EA no w\u0142a\u015bnie, \u003Cstrong\u003ECoffeeScript\u003C\/strong\u003E. \u017bywy dow\u00f3d, \u017ce nawet tworzenie JavaScript\u00f3w mo\u017ce by\u0107 przyjemne (s\u0142owo daj\u0119, nie uwierzy\u0142bym, gdybym nie spr\u00f3bowa\u0142). W JS to dopiero jest nadmiar nawias\u00f3w i klamer:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Esse = new EventSource(Routing.generate(\u0027conversation_check\u0027));\nsse.addEventListener(\u0027conversation\u0027, function(e) {\n  if (e.data == \u0027test\u0027 || e.data == \u0027dev\u0027) { return; }\n  $.post(Routing.generate(\u0027conversation_fetch\u0027), { ids: e.data }, function(data) {\n    conversation.html(data);\n  });\n}, false);\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETa sama funkcjonalno\u015b\u0107 w CoffeeScripcie wygl\u0105da nast\u0119puj\u0105co:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Esse = new EventSource Routing.generate \u0027conversation_check\u0027\nsse.addEventListener \u0027conversation\u0027, (e) -\u0026gt;\n  return if e.data in [\u0027test\u0027, \u0027dev\u0027]\n  $.post(Routing.generate(\u0027conversation_fetch\u0027), { ids: e.data }, (data) -\u0026gt;\n    conversation.html(data)\n  )\n, false\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWystarczy\u0142o zast\u0105pienie sk\u0142adni \u003Ccode\u003Efunction(a) {...}\u003C\/code\u003E prostym \u003Ccode\u003E(a) -\u0026gt; ...\u003C\/code\u003E, zmiana klamer na wci\u0119cia oraz mo\u017cliwo\u015b\u0107 pomini\u0119cia niekt\u00f3rych nawias\u00f3w w parametrach funkcji \u2013 i voil\u00e0! Mniej klepania w klawiatur\u0119 i doszukiwania si\u0119 par nawias\u00f3w, a tre\u015bci tyle samo!\u003C\/p\u003E\n\u003Cp\u003ENie spos\u00f3b si\u0119 nachwali\u0107 wszystkich ficzer\u00f3w CoffeeScriptu... JSON-owe obiekty mo\u017cna w nim definiowa\u0107 podobnie jak w \u003Ca href=\u0022http:\/\/yaml.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E YAML-u\u003C\/a\u003E, p\u0119tl\u0119 mo\u017cna od 1 do 100 zawrze\u0107 w kr\u00f3ciutkim zapisie \u003Ccode\u003E1..100\u003C\/code\u003E, zmiennych nie trzeba deklarowa\u0107, mo\u017cna im przypisywa\u0107 warto\u015bci do wielu na raz (a nawet zamienia\u0107 je warto\u015bciami w jednej linijce: \u003Ccode\u003E[foo, bar] = [bar, foo]\u003C\/code\u003E i tyle!). Najlepiej po prostu przejrze\u0107 jego \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E stron\u0119 domow\u0105\u003C\/a\u003E i milcze\u0107 w \u003Cstrong\u003Ezachwycie\u003C\/strong\u003E!\u003C\/p\u003E\n\u003Cp\u003ER\u00f3wnie\u017c w przypadku HTML-a istnieje wiele technologii, kt\u00f3re pozwalaj\u0105 na wygenerowanie go na postawie bardziej wyrafinowanych j\u0119zyk\u00f3w. Lecz tutaj to troch\u0119 co innego. Mowa o template engines takich jak \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/twig.sensiolabs.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Twig\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.smarty.net\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Smarty\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/haml.info\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Haml\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.stuartellis.eu\/articles\/erb\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Erb\u003C\/a\u003E\u003C\/strong\u003E \u2013 one jednak s\u0105 kompilowane do j\u0119zyk\u00f3w wykonywanych po stronie serwera (PHP, Ruby, Python...), wi\u0119c niezbyt pasuj\u0105 do mojego zestawienia. (Nota bene w Hamlu jeszcze bardziej zredukowana jest klamrowa redundancja: z \u003Ccode\u003E\u0026lt;html\u0026gt;\u0026lt;\/html\u0026gt;\u003C\/code\u003E robi si\u0119 zwyk\u0142e \u003Ccode\u003E%html\u003C\/code\u003E)\u003C\/p\u003E\n\u003Cp\u003EPotrafi\u0119 znale\u017a\u0107 tylko dwie wady ca\u0142ej tej rodziny technologii w por\u00f3wnaniu do \u003Cem\u003E\u015bwi\u0119tej tr\u00f3jcy\u003C\/em\u003E. Po pierwsze, tak jak przegl\u0105darki, tak samo frontendowi programi\u015bci tr\u00f3jc\u0119 znaj\u0105 z ca\u0142\u0105 pewno\u015bci\u0105, czego nie zawsze mo\u017cna powiedzie\u0107 o jej m\u0142odszym rodze\u0144stwie. Wi\u0119c je\u015bli kto\u015b dostanie po tobie projekt, w kt\u00f3rym u\u017cywa\u0142e\u015b Sassa czy CoffeeScriptu, mo\u017ce nie by\u0107 mu zbyt kolorowo. Z drugiej jednak strony, s\u0105 to przecie\u017c technologie \u003Cstrong\u003Ebardzo \u0142atwe do przyswojenia\u003C\/strong\u003E, a zarazem niezmiernie przydatne i wygodne. Wi\u0119c chyba tylko wy\u015bwiadczy\u0142by\u015b mu przys\u0142ug\u0119, prawda?\u003C\/p\u003E\n\u003Cp\u003EPo drugie natomiast, kompilowanie trwa i wymaga zachodu. Wystarczy jednak zainstalowa\u0107 \u003Ca href=\u0022http:\/\/bower.io\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Bowera\u003C\/a\u003E albo skonfigurowa\u0107 sobie watchera w \u003Ca href=\u0022https:\/\/www.jetbrains.com\/phpstorm\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E PhpStormie\u003C\/a\u003E, aby ka\u017cde zapisanie pliku automatycznie uruchamia\u0142o kompilacj\u0119. Naprawd\u0119, wygodniej ju\u017c si\u0119 tego zrobi\u0107 nie da!\u003C\/p\u003E\n\u003Cp\u003EA poza tym \u003Cstrong\u003Esame plusy\u003C\/strong\u003E. Je\u015bli tworzysz strony, a jeszcze nie znasz tych technologii \u2013 \u003Cstrong\u003Ekoniecznie je wypr\u00f3buj!\u003C\/strong\u003E Z odrobin\u0105 wprawy i do\u015bwiadczenia, po\u0142owa twoich frontendowych problem\u00f3w mo\u017ce znikn\u0105\u0107.\u003C\/p\u003E","words":1075,"readTime":5,"lang":"pl"}}}}}