├── examples ├── chapter_3 │ ├── examples │ │ ├── 3.1.1 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.4.4 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.5.2 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.7.2 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.5.3 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.5.1 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.2.2 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.4.2 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.5.4 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.4.1 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.2.1 │ │ │ ├── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ │ └── styles │ │ │ │ ├── styles.css │ │ │ │ └── _styles.less │ │ ├── 3.7.1 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 3.4.5 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ └── 3.4.3 │ │ │ ├── styles.css │ │ │ └── _styles.less │ └── homework │ │ ├── less │ │ ├── styles.less │ │ ├── _typography.less │ │ ├── _grid.less │ │ ├── _mixins.less │ │ ├── _core.less │ │ ├── _buttons.less │ │ └── _normalize.less │ │ ├── index.html │ │ └── styles.css ├── chapter_4 │ ├── examples │ │ ├── 4.3.2 │ │ │ ├── styles │ │ │ │ ├── styles.css │ │ │ │ └── less │ │ │ │ │ ├── main.less │ │ │ │ │ └── components │ │ │ │ │ └── _styles.less │ │ │ └── images │ │ │ │ └── avatar.jpg │ │ ├── 4.3.3 │ │ │ ├── _styles.css │ │ │ ├── styles.css │ │ │ ├── _styles.less │ │ │ └── test.svg │ │ ├── 4.3.1 │ │ │ ├── styles │ │ │ │ ├── styles.css │ │ │ │ └── less │ │ │ │ │ └── _styles.less │ │ │ └── images │ │ │ │ └── avatar.jpg │ │ ├── 4.2.1 │ │ │ ├── styles.css │ │ │ └── styles.less │ │ └── 4.2.2 │ │ │ ├── styles.css │ │ │ └── styles.less │ └── homework │ │ ├── task_1 │ │ ├── styles.css │ │ └── styles.less │ │ └── task_2 │ │ ├── styles.css │ │ ├── less │ │ └── styles.less │ │ └── index.html ├── chapter_2 │ ├── examples │ │ ├── 2.6.1 │ │ │ ├── import │ │ │ │ ├── _mail.css │ │ │ │ ├── _yahoo.less │ │ │ │ ├── _yandex.less │ │ │ │ └── _duckduckgo.less │ │ │ ├── _styles.less │ │ │ └── styles.css │ │ ├── 2.6.6 │ │ │ ├── import │ │ │ │ ├── _yahoo.less │ │ │ │ ├── _yandex.less │ │ │ │ └── _duckduckgo.less │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.6.7 │ │ │ ├── import │ │ │ │ ├── _yandex.less │ │ │ │ └── _duckduckgo.less │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.6.3 │ │ │ ├── import │ │ │ │ └── _duckduckgo.less │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.4.1 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.6.2 │ │ │ ├── _styles.less │ │ │ ├── import │ │ │ │ └── _mail.css │ │ │ └── styles.css │ │ ├── 2.6.5 │ │ │ ├── _styles.less │ │ │ ├── import │ │ │ │ └── _mail.css │ │ │ └── styles.css │ │ ├── 2.6.4 │ │ │ ├── styles.css │ │ │ ├── import │ │ │ │ └── _yandex.less │ │ │ └── _styles.less │ │ ├── 2.3.1 │ │ │ ├── styles.css │ │ │ ├── _styles.less │ │ │ └── index.html │ │ ├── 2.4.2 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.4.5 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.1 │ │ │ ├── nested.css │ │ │ ├── special.css │ │ │ ├── _nested.less │ │ │ ├── _special.less │ │ │ ├── basic.css │ │ │ └── _basic.less │ │ ├── 2.4.3 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.3.2 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.5.1 │ │ │ ├── _styles.less │ │ │ └── styles.css │ │ ├── 2.5.2 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.3.5 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.4.4 │ │ │ ├── _styles.less │ │ │ └── styles.css │ │ ├── 2.5.3 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.3.6 │ │ │ ├── _styles.less │ │ │ └── styles.css │ │ ├── 2.2.2 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ ├── 2.2.1 │ │ │ └── styles.css │ │ ├── 2.3.3 │ │ │ ├── styles.css │ │ │ └── _styles.less │ │ └── 2.3.4 │ │ │ ├── styles.css │ │ │ └── _styles.less │ └── homework │ │ ├── less │ │ ├── _header.less │ │ ├── styles.less │ │ ├── _grid.less │ │ ├── _typography.less │ │ ├── _core.less │ │ ├── _gallery.less │ │ └── _normalize.less │ │ ├── images │ │ ├── gallery-photo-1.png │ │ ├── gallery-photo-2.png │ │ ├── gallery-photo-3.png │ │ ├── gallery-photo-4.png │ │ ├── gallery-photo-5.png │ │ ├── gallery-photo-6.png │ │ ├── gallery-photo-7.png │ │ ├── gallery-photo-8.png │ │ └── gallery-photo-9.png │ │ ├── index.html │ │ └── styles.css ├── chapter_6 │ └── examples │ │ ├── 6.1.2 │ │ ├── script.js │ │ └── styles.less │ │ ├── 6.1.1 │ │ ├── script.js │ │ └── styles.less │ │ ├── 6.1.3 │ │ ├── script.js │ │ └── styles.less │ │ └── 6.1.4 │ │ ├── script.js │ │ └── styles.less ├── chapter_1 │ ├── 1.4.1 │ │ ├── less │ │ │ └── _styles.less │ │ └── index.html │ ├── 1.4.2 │ │ ├── less │ │ │ └── _styles.less │ │ └── index.html │ ├── 1.4.4 │ │ ├── styles.map │ │ ├── styles.css │ │ ├── index.html │ │ └── _styles.less │ ├── 1.4.3 │ │ ├── less │ │ │ └── _styles.less │ │ └── index.html │ ├── test.css │ └── _test.less └── chapter_5 │ ├── examples │ ├── 5.2.1 │ │ ├── styles.css │ │ └── styles.less │ ├── 5.1.1 │ │ ├── styles.css │ │ └── styles.less │ └── 5.2.2 │ │ ├── styles.css │ │ └── styles.less │ └── homework │ ├── styles.css │ └── styles.less ├── cover.jpg ├── images ├── chapter_2_homework_1.png ├── chapter_2_homework_2.png ├── chapter_2_homework_3.png ├── chapter_2_homework_4.png ├── chapter_3_homework_1.png ├── chapter_3_homework_2.png ├── chapter_4_homework_1.png ├── chapter_1_example_141.png ├── chapter_1_example_142.png ├── chapter_1_example_144.png ├── chapter_1_less_to_css.png ├── chapter_2_example_222.png └── chapter_2_example_265.png ├── .vscode └── settings.json ├── chapter_0 ├── thanks.md ├── audience.md └── introduction.md ├── chapter_5 ├── intro.md ├── homework.md └── if.md ├── .gitignore ├── chapter_1 ├── intro.md ├── preprocessors.md ├── verge-less-css.md ├── usage-plugins.md └── css-reprocessors.md ├── chapter_6 ├── intro.md ├── features-overview.md └── working-with-variables-and-mixins.md ├── chapter_3 ├── intro.md ├── homework.md ├── variable-names.md ├── additional-features-of-mixins.md ├── working-with-rulesets.md └── using-mixins.md ├── chapter_4 ├── intro.md ├── homework.md ├── math-functions.md ├── merge-properties.md ├── working-with-data-types-and-units.md └── working-with-images.md ├── chapter_2 ├── intro.md ├── comments.md ├── homework.md ├── nested-rules.md └── media-queries.md ├── CONTRIBUTING.md ├── README.md ├── CHANGELOG.md └── SUMMARY.md /examples/chapter_3/examples/3.1.1/styles.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.2/styles/styles.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.4/styles.css: -------------------------------------------------------------------------------- 1 | .test { 2 | content: 6; 3 | } 4 | -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.3/_styles.css: -------------------------------------------------------------------------------- 1 | .test { 2 | content: ; 3 | } 4 | -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.3/styles.css: -------------------------------------------------------------------------------- 1 | .test { 2 | content: ; 3 | } 4 | -------------------------------------------------------------------------------- /examples/chapter_4/homework/task_1/styles.css: -------------------------------------------------------------------------------- 1 | .test { 2 | content: 11; 3 | } 4 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.1/import/_mail.css: -------------------------------------------------------------------------------- 1 | .mail { 2 | color: #168de2; 3 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.1/import/_yahoo.less: -------------------------------------------------------------------------------- 1 | .yahoo { 2 | color: #400191; 3 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.6/import/_yahoo.less: -------------------------------------------------------------------------------- 1 | .yahoo { 2 | color: #400191; 3 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.5.2/styles.css: -------------------------------------------------------------------------------- 1 | .class { 2 | color: #777777; 3 | } 4 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/cover.jpg -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.1/import/_yandex.less: -------------------------------------------------------------------------------- 1 | .yandex { 2 | color: #ffcc00; 3 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.6/import/_yandex.less: -------------------------------------------------------------------------------- 1 | .yandex { 2 | color: #ffcc00; 3 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.7/import/_yandex.less: -------------------------------------------------------------------------------- 1 | .yandex { 2 | color: #ffcc00; 3 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.7.2/styles.css: -------------------------------------------------------------------------------- 1 | selector { 2 | variable: global; 3 | } 4 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.1/import/_duckduckgo.less: -------------------------------------------------------------------------------- 1 | .duckduckgo { 2 | color: #de5833; 3 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.3/import/_duckduckgo.less: -------------------------------------------------------------------------------- 1 | .duckduckgo { 2 | color: #de5833; 3 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.6/import/_duckduckgo.less: -------------------------------------------------------------------------------- 1 | .duckduckgo { 2 | color: #de5833; 3 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.7/import/_duckduckgo.less: -------------------------------------------------------------------------------- 1 | .duckduckgo { 2 | color: #de5833; 3 | } -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.2/styles/less/main.less: -------------------------------------------------------------------------------- 1 | @import "components/_styles.less"; 2 | -------------------------------------------------------------------------------- /examples/chapter_6/examples/6.1.2/script.js: -------------------------------------------------------------------------------- 1 | (function(args) { 2 | return args; 3 | })('@{arguments}') -------------------------------------------------------------------------------- /examples/chapter_1/1.4.1/less/_styles.less: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f5f5f5; 3 | color: #777; 4 | } -------------------------------------------------------------------------------- /examples/chapter_6/examples/6.1.1/script.js: -------------------------------------------------------------------------------- 1 | (function(a, b) { 2 | return a + b; 3 | })('@{a}', '@{b}'); 4 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.5.3/styles.css: -------------------------------------------------------------------------------- 1 | .class { 2 | color: #000000; 3 | background-color: #ffffff; 4 | } 5 | -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.1/styles/styles.css: -------------------------------------------------------------------------------- 1 | .logo { 2 | content: "460px 460px [460px x 460px]"; 3 | } 4 | -------------------------------------------------------------------------------- /examples/chapter_4/homework/task_2/styles.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: #000000; 3 | } 4 | a:hover { 5 | color: #737373; 6 | } 7 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.3/styles.css: -------------------------------------------------------------------------------- 1 | @import "import/_duckduckgo.less"; 2 | .canonium { 3 | color: #53599a; 4 | } 5 | -------------------------------------------------------------------------------- /examples/chapter_1/1.4.2/less/_styles.less: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f5f5f5; 3 | color: #777; 4 | } 5 | 6 | .thisIsMySelector -------------------------------------------------------------------------------- /images/chapter_2_homework_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_2_homework_1.png -------------------------------------------------------------------------------- /images/chapter_2_homework_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_2_homework_2.png -------------------------------------------------------------------------------- /images/chapter_2_homework_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_2_homework_3.png -------------------------------------------------------------------------------- /images/chapter_2_homework_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_2_homework_4.png -------------------------------------------------------------------------------- /images/chapter_3_homework_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_3_homework_1.png -------------------------------------------------------------------------------- /images/chapter_3_homework_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_3_homework_2.png -------------------------------------------------------------------------------- /images/chapter_4_homework_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_4_homework_1.png -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.1/styles.css: -------------------------------------------------------------------------------- 1 | .class-1, 2 | .class-2, 3 | .class-3 { 4 | background-color: #fff; 5 | color: #000; 6 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.2/_styles.less: -------------------------------------------------------------------------------- 1 | .canonium { 2 | color: #53599a; 3 | } 4 | 5 | @import (less) "import/_mail.css"; 6 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.2/import/_mail.css: -------------------------------------------------------------------------------- 1 | .mail { 2 | color: #168de2; 3 | } 4 | 5 | .mail .orange { 6 | color: #ffa930; 7 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.3/_styles.less: -------------------------------------------------------------------------------- 1 | @import (css) "import/_duckduckgo.less"; 2 | 3 | .canonium { 4 | color: #53599a; 5 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.5/_styles.less: -------------------------------------------------------------------------------- 1 | @import (less, inline) "import/_mail.css"; 2 | 3 | .canonium { 4 | color: #53599a; 5 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.5/import/_mail.css: -------------------------------------------------------------------------------- 1 | .mail { 2 | color: #168de2; 3 | filter: ms:alwaysHasItsOwnSyntax.For.Stuff(); 4 | } -------------------------------------------------------------------------------- /images/chapter_1_example_141.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_1_example_141.png -------------------------------------------------------------------------------- /images/chapter_1_example_142.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_1_example_142.png -------------------------------------------------------------------------------- /images/chapter_1_example_144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_1_example_144.png -------------------------------------------------------------------------------- /images/chapter_1_less_to_css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_1_less_to_css.png -------------------------------------------------------------------------------- /images/chapter_2_example_222.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_2_example_222.png -------------------------------------------------------------------------------- /images/chapter_2_example_265.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/images/chapter_2_example_265.png -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.4/styles.css: -------------------------------------------------------------------------------- 1 | .canonium { 2 | color: #53599a; 3 | } 4 | .topbar { 5 | background-color: #e4491b; 6 | } 7 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.5.1/styles.css: -------------------------------------------------------------------------------- 1 | .class { 2 | color: #777777; 3 | color: #000000; 4 | background-color: #ffffff; 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "editor.wrappingColumn": 100 4 | } 5 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.1/styles.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: #777; 3 | text-decoration: none; 4 | } 5 | a:hover { 6 | color: #a31515; 7 | } 8 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.2.2/styles.css: -------------------------------------------------------------------------------- 1 | .grey { 2 | background-color: #fafafa; 3 | } 4 | .red { 5 | background-color: #ffebee; 6 | } 7 | -------------------------------------------------------------------------------- /examples/chapter_2/homework/less/_header.less: -------------------------------------------------------------------------------- 1 | .page-title { 2 | background-color: #ecf0f1; 3 | padding: 50px 10px; 4 | text-align: center; 5 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.1/_styles.less: -------------------------------------------------------------------------------- 1 | a { 2 | color: #777; 3 | text-decoration: none; 4 | 5 | &:hover { 6 | color: #a31515; 7 | } 8 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.4/import/_yandex.less: -------------------------------------------------------------------------------- 1 | .yandex { 2 | color: #ffcc00; 3 | } 4 | 5 | .yandex-topbar { 6 | background-color: #e4491b; 7 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.2/styles.css: -------------------------------------------------------------------------------- 1 | .link { 2 | transition-timing-function: ease; 3 | transition-duration: 1s; 4 | transition-property: all; 5 | } 6 | -------------------------------------------------------------------------------- /chapter_0/thanks.md: -------------------------------------------------------------------------------- 1 | # Благодарности 2 | 3 | Выражаю огромную благодарность всем людям, принимавшим участие в написании этой книги. Без вас у меня ничего бы не вышло. 4 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.5.4/styles.css: -------------------------------------------------------------------------------- 1 | .class { 2 | color: #333333; 3 | background-color: #f5f5f5; 4 | color: #f5f5f5; 5 | background-color: #333333; 6 | } 7 | -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.1/images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_4/examples/4.3.1/images/avatar.jpg -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.2/images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_4/examples/4.3.2/images/avatar.jpg -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.2/styles.css: -------------------------------------------------------------------------------- 1 | .class-1, 2 | .selector { 3 | background-color: #fff; 4 | } 5 | .class-2, 6 | .selector { 7 | background-color: #fff; 8 | } 9 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.1/styles.css: -------------------------------------------------------------------------------- 1 | .navbar:before, 2 | .navbar:after { 3 | display: table; 4 | content: ""; 5 | } 6 | .navbar:after { 7 | clear: both; 8 | } 9 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.5/styles.css: -------------------------------------------------------------------------------- 1 | .item { 2 | background-color: #fff; 3 | border: 1px solid #ddd; 4 | } 5 | .item .header, 6 | .article { 7 | padding: 25px; 8 | } 9 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.5/styles.css: -------------------------------------------------------------------------------- 1 | .mail { 2 | color: #168de2; 3 | filter: ms:alwaysHasItsOwnSyntax.For.Stuff(); 4 | } 5 | .canonium { 6 | color: #53599a; 7 | } 8 | -------------------------------------------------------------------------------- /examples/chapter_2/homework/images/gallery-photo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_2/homework/images/gallery-photo-1.png -------------------------------------------------------------------------------- /examples/chapter_2/homework/images/gallery-photo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_2/homework/images/gallery-photo-2.png -------------------------------------------------------------------------------- /examples/chapter_2/homework/images/gallery-photo-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_2/homework/images/gallery-photo-3.png -------------------------------------------------------------------------------- /examples/chapter_2/homework/images/gallery-photo-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_2/homework/images/gallery-photo-4.png -------------------------------------------------------------------------------- /examples/chapter_2/homework/images/gallery-photo-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_2/homework/images/gallery-photo-5.png -------------------------------------------------------------------------------- /examples/chapter_2/homework/images/gallery-photo-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_2/homework/images/gallery-photo-6.png -------------------------------------------------------------------------------- /examples/chapter_2/homework/images/gallery-photo-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_2/homework/images/gallery-photo-7.png -------------------------------------------------------------------------------- /examples/chapter_2/homework/images/gallery-photo-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_2/homework/images/gallery-photo-8.png -------------------------------------------------------------------------------- /examples/chapter_2/homework/images/gallery-photo-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_2/homework/images/gallery-photo-9.png -------------------------------------------------------------------------------- /examples/chapter_2/homework/less/styles.less: -------------------------------------------------------------------------------- 1 | @import "_normalize"; 2 | @import "_core"; 3 | @import "_typography"; 4 | @import "_grid"; 5 | @import "_header"; 6 | @import "_gallery"; -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.2.1/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_3/examples/3.2.1/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /examples/chapter_3/homework/less/styles.less: -------------------------------------------------------------------------------- 1 | @import "_mixins"; 2 | @import "_normalize"; 3 | @import "_core"; 4 | @import "_typography"; 5 | @import "_grid"; 6 | @import "_buttons"; -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.1/nested.css: -------------------------------------------------------------------------------- 1 | /* 2 | // Смешивание комментариев 3 | */ 4 | .test-1 { 5 | background-color: #fff; 6 | } 7 | .test-2 { 8 | color: #000; 9 | } 10 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.2/styles.css: -------------------------------------------------------------------------------- 1 | .canonium { 2 | color: #53599a; 3 | } 4 | .mail { 5 | color: #168de2; 6 | } 7 | .mail .orange { 8 | color: #ffa930; 9 | } 10 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.7/styles.css: -------------------------------------------------------------------------------- 1 | .duckduckgo { 2 | color: #de5833; 3 | } 4 | .yandex { 5 | color: #ffcc00; 6 | } 7 | .canonium { 8 | color: #53599a; 9 | } 10 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.4/_styles.less: -------------------------------------------------------------------------------- 1 | .canonium { 2 | color: #53599a; 3 | } 4 | 5 | @import (reference) "import/_yandex"; 6 | 7 | .topbar { 8 | &:extend(.yandex-topbar); 9 | } -------------------------------------------------------------------------------- /examples/chapter_6/examples/6.1.3/script.js: -------------------------------------------------------------------------------- 1 | (function(args) { 2 | return args; 3 | })((function() { 4 | var args = '@{arguments}'; 5 | return args.replace(/^\[|\]$/g, '') 6 | })()) 7 | -------------------------------------------------------------------------------- /examples/chapter_6/examples/6.1.4/script.js: -------------------------------------------------------------------------------- 1 | (function(args) { 2 | return args; 3 | })((function() { 4 | var args = '@{arguments}'; 5 | return args.replace(/^\[|\]$/g, '') 6 | })()); 7 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.1/special.css: -------------------------------------------------------------------------------- 1 | /*! Комментарий, который будет всегда сохраняться */.test-1{background-color:#fff}/*! Комментарий, который будет всегда сохраняться !*/.test-2{color:#000} -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.2.1/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_3/examples/3.2.1/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.2.1/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_3/examples/3.2.1/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.4/_styles.less: -------------------------------------------------------------------------------- 1 | @global: 3; 2 | 3 | .calc(@a: 1, @b: 2, @c: @global) { 4 | @d: @a + @b + @c; 5 | content: @d; 6 | } 7 | 8 | .test { 9 | .calc(); 10 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.2.1/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_3/examples/3.2.1/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.2.1/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrmlnc/less-guidebook-for-beginners/HEAD/examples/chapter_3/examples/3.2.1/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /examples/chapter_6/examples/6.1.1/styles.less: -------------------------------------------------------------------------------- 1 | .mixin(@a, @b) { 2 | @js: ~`(function(a, b) { return a + b })('@{a}', '@{b}')`; 3 | content: @js; 4 | } 5 | 6 | .test-js { 7 | .mixin(1, 2); 8 | } 9 | -------------------------------------------------------------------------------- /examples/chapter_6/examples/6.1.2/styles.less: -------------------------------------------------------------------------------- 1 | .mixin(...) { 2 | @js: ~`(function(args){ return args; })('@{arguments}')`; 3 | 4 | content: @js; 5 | } 6 | 7 | .test-js { 8 | .mixin(3, 123); 9 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.3/styles.css: -------------------------------------------------------------------------------- 1 | .global-header, 2 | .global-navigation { 3 | background-color: #fff; 4 | color: #000; 5 | } 6 | .global-navigation { 7 | border: 1px solid #ddd; 8 | } 9 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.7/_styles.less: -------------------------------------------------------------------------------- 1 | @import "import/_duckduckgo"; 2 | @import (optional) "import/_yahoo"; 3 | @import (optional) "import/_yandex"; 4 | 5 | .canonium { 6 | color: #53599a; 7 | } -------------------------------------------------------------------------------- /examples/chapter_5/examples/5.2.1/styles.css: -------------------------------------------------------------------------------- 1 | .col-1 { 2 | width: 25%; 3 | } 4 | .col-2 { 5 | width: 50%; 6 | } 7 | .col-3 { 8 | width: 75%; 9 | } 10 | .col-4 { 11 | width: 100%; 12 | } 13 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.1/_styles.less: -------------------------------------------------------------------------------- 1 | .class-1 { 2 | background-color: #fff; 3 | color: #000; 4 | } 5 | 6 | .class-2:extend(.class-1) {} 7 | 8 | .class-3 { 9 | &:extend(.class-1); 10 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.7.1/styles.css: -------------------------------------------------------------------------------- 1 | .class { 2 | background-color: #000; 3 | } 4 | @media (min-width: 768px) and (max-width: 1199px) { 5 | .class { 6 | background-color: #fff; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.3/_styles.less: -------------------------------------------------------------------------------- 1 | .global-header { 2 | background-color: #fff; 3 | color: #000; 4 | } 5 | 6 | .global-navigation { 7 | &:extend(.global-header); 8 | border: 1px solid #ddd; 9 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.2/_styles.less: -------------------------------------------------------------------------------- 1 | .class-1 { 2 | background-color: #fff; 3 | } 4 | 5 | .class-2 { 6 | background-color: #fff; 7 | } 8 | 9 | .selector { 10 | &:extend(.class-1, .class-2); 11 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.1/_styles.less: -------------------------------------------------------------------------------- 1 | @import "import/_mail.css"; 2 | @import "import/_duckduckgo"; 3 | 4 | .canonium { 5 | color: #53599a; 6 | } 7 | 8 | @import "import/_yahoo"; 9 | @import "import/_yandex"; -------------------------------------------------------------------------------- /examples/chapter_1/1.4.4/styles.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["_styles.less"],"names":[],"mappings":"AAIA;EACE,kBAAA;EACA,yBAAA;EACA,cAAA;;AAHF,cAKE;EACE,eAAA;EACA,iBAAA;;AAPJ,cAKE,GAIE;EACE,eAAA;EACA,iBAAA","file":"undefined"} -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.2/styles.css: -------------------------------------------------------------------------------- 1 | .class-1 { 2 | background-color: #fff; 3 | } 4 | .class-1.class-2 { 5 | color: #000; 6 | } 7 | /* Alternative */ 8 | .class-1.class-2 { 9 | color: #000; 10 | } 11 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.2/_styles.less: -------------------------------------------------------------------------------- 1 | .class-1 { 2 | background-color: #fff; 3 | 4 | &.class-2 { 5 | color: #000; 6 | } 7 | } 8 | 9 | /* Alternative */ 10 | .class-1.class-2 { 11 | color: #000; 12 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.5.2/_styles.less: -------------------------------------------------------------------------------- 1 | .mixin(@color: #777) { 2 | color: @color; 3 | } 4 | 5 | .mixin(@color, @bg) { 6 | color: @color; 7 | background-color: @bg; 8 | } 9 | 10 | .class { 11 | .mixin(); 12 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.5/_styles.less: -------------------------------------------------------------------------------- 1 | .item { 2 | background-color: #fff; 3 | border: 1px solid #ddd; 4 | 5 | .header { 6 | padding: 25px; 7 | } 8 | } 9 | 10 | .article { 11 | &:extend(.item .header); 12 | } -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.3/_styles.less: -------------------------------------------------------------------------------- 1 | .isunit(@value, @unit) { 2 | @exValue: e(@value); 3 | @exUnit: e(@unit); 4 | 5 | 6 | content: get-unit(@exValue); 7 | } 8 | 9 | .test { 10 | .isunit("10px", "px"); 11 | } 12 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.5.1/_styles.less: -------------------------------------------------------------------------------- 1 | .mixin(@color: #777) { 2 | color: @color; 3 | } 4 | 5 | .mixin(@color: #000, @bg: #fff) { 6 | color: @color; 7 | background-color: @bg; 8 | } 9 | 10 | .class { 11 | .mixin(); 12 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.5.3/_styles.less: -------------------------------------------------------------------------------- 1 | .mixin(@color: #777) { 2 | color: @color; 3 | } 4 | 5 | .mixin(@color, @bg: #fff) { 6 | color: @color; 7 | background-color: @bg; 8 | } 9 | 10 | .class { 11 | .mixin(#000); 12 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.5.1/_styles.less: -------------------------------------------------------------------------------- 1 | .one { 2 | @media (min-width: 768px) { 3 | background-color: #f5f5f5; 4 | 5 | .two { 6 | @media (max-width: 992px) { 7 | color: #000; 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.5.1/styles.css: -------------------------------------------------------------------------------- 1 | @media (min-width: 768px) { 2 | .one { 3 | background-color: #f5f5f5; 4 | } 5 | } 6 | @media (min-width: 768px) and (max-width: 992px) { 7 | .one .two { 8 | color: #000; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.1/_nested.less: -------------------------------------------------------------------------------- 1 | /* 2 | // Смешивание комментариев 3 | */ 4 | 5 | .test-1 { 6 | background-color: #fff; 7 | } 8 | 9 | // /* Этот комментарий вложен в другой комментарий */ 10 | 11 | .test-2 { 12 | color: #000; 13 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.1/styles.css: -------------------------------------------------------------------------------- 1 | @import "import/_mail.css"; 2 | .duckduckgo { 3 | color: #de5833; 4 | } 5 | .canonium { 6 | color: #53599a; 7 | } 8 | .yahoo { 9 | color: #400191; 10 | } 11 | .yandex { 12 | color: #ffcc00; 13 | } 14 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.1/_styles.less: -------------------------------------------------------------------------------- 1 | .clearfix() { 2 | &:before, 3 | &:after { 4 | display: table; 5 | content: ""; 6 | } 7 | 8 | &:after { 9 | clear: both; 10 | } 11 | } 12 | 13 | .navbar { 14 | .clearfix(); 15 | } -------------------------------------------------------------------------------- /examples/chapter_4/homework/task_2/less/styles.less: -------------------------------------------------------------------------------- 1 | @color: #333; 2 | @color-dark: darken(@color, 25%); 3 | @color-light: lighten(@color, 25%); 4 | 5 | a { 6 | color: @color-dark; 7 | 8 | &:hover { 9 | color: @color-light; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/chapter_5/examples/5.1.1/styles.css: -------------------------------------------------------------------------------- 1 | .test-one { 2 | padding: 10px; 3 | } 4 | .test-two { 5 | padding: 10px 5px; 6 | } 7 | .test-three { 8 | padding: 10px 5px 15px; 9 | } 10 | .test-four { 11 | padding: 10px 5px 15px 20px; 12 | } 13 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.1/_special.less: -------------------------------------------------------------------------------- 1 | /*! Комментарий, который будет всегда сохраняться */ 2 | 3 | .test-1 { 4 | background-color: #fff; 5 | } 6 | 7 | /*! Комментарий, который будет всегда сохраняться !*/ 8 | 9 | .test-2 { 10 | color: #000; 11 | } -------------------------------------------------------------------------------- /examples/chapter_6/examples/6.1.3/styles.less: -------------------------------------------------------------------------------- 1 | .mixin(...) { 2 | @js: ~`function(args){return args}(function(){var args='@{arguments}';return args.replace(/^\[|\]$/g,'')}())`; 3 | 4 | content: @js; 5 | } 6 | 7 | .test-js { 8 | .mixin(3, 123); 9 | } 10 | -------------------------------------------------------------------------------- /examples/chapter_3/homework/less/_typography.less: -------------------------------------------------------------------------------- 1 | // Заголовки 2 | h1, 3 | h2, 4 | h3, 5 | h4, 6 | h5, 7 | h6 { 8 | margin-top: 2em; 9 | margin-bottom: 1em; 10 | } 11 | 12 | h1 { 13 | font-weight: 300; 14 | line-height: 1.25; 15 | font-size: 3.2rem; 16 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.5.2/styles.css: -------------------------------------------------------------------------------- 1 | @media screen { 2 | .one { 3 | background-color: #fff; 4 | } 5 | } 6 | @media screen and (min-width: 992px) { 7 | .two { 8 | color: #777; 9 | } 10 | } 11 | .three { 12 | border-right: 1px solid #000; 13 | } 14 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.5/styles.css: -------------------------------------------------------------------------------- 1 | .test-1 { 2 | color: #333333; 3 | } 4 | .test-2 { 5 | color: #333333; 6 | background-color: #ffffff; 7 | } 8 | .test-3 { 9 | color: #333333; 10 | background-color: #ffffff; 11 | border: 1px solid #dddddd; 12 | } 13 | -------------------------------------------------------------------------------- /examples/chapter_5/homework/styles.css: -------------------------------------------------------------------------------- 1 | .color-black { 2 | color: #000000; 3 | } 4 | .color-red { 5 | color: #ff0000; 6 | } 7 | .color-purple { 8 | color: #800080; 9 | } 10 | .color-green { 11 | color: #008000; 12 | } 13 | .color-blue { 14 | color: #0000ff; 15 | } 16 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.2/_styles.less: -------------------------------------------------------------------------------- 1 | .transition(@function: ease, @duration: .3s, @property: all) { 2 | transition-timing-function: @function; 3 | transition-duration: @duration; 4 | transition-property: @property; 5 | } 6 | 7 | .link { 8 | .transition(@duration: 1s); 9 | } -------------------------------------------------------------------------------- /examples/chapter_4/homework/task_2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Task_2 6 | 7 | 8 | 9 | This is link 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.5/styles.css: -------------------------------------------------------------------------------- 1 | .header .item + .header .item { 2 | color: red; 3 | } 4 | .header .item .header .item { 5 | color: green; 6 | } 7 | .header .item.header .item { 8 | color: blue; 9 | } 10 | .header .item, 11 | .header .item-box { 12 | color: yellow; 13 | } 14 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.4/_styles.less: -------------------------------------------------------------------------------- 1 | .global-header { 2 | background-color: #fff; 3 | 4 | .area { 5 | text-align: center; 6 | } 7 | } 8 | 9 | .global-header:hover { 10 | background-color: #000; 11 | } 12 | 13 | .global-footer { 14 | &:extend(.global-header all); 15 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.4.4/styles.css: -------------------------------------------------------------------------------- 1 | .global-header, 2 | .global-footer { 3 | background-color: #fff; 4 | } 5 | .global-header .area, 6 | .global-footer .area { 7 | text-align: center; 8 | } 9 | .global-header:hover, 10 | .global-footer:hover { 11 | background-color: #000; 12 | } 13 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.3/styles.css: -------------------------------------------------------------------------------- 1 | .block { 2 | transition-timing-function: linear; 3 | transition-duration: 0.3s; 4 | transition-property: all; 5 | } 6 | .link { 7 | transition-timing-function: linear; 8 | transition-duration: 0.5s; 9 | transition-property: all; 10 | } 11 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.5/_styles.less: -------------------------------------------------------------------------------- 1 | .header { 2 | .item { 3 | & + & { 4 | color: red; 5 | } 6 | 7 | & & { 8 | color: green; 9 | } 10 | 11 | && { 12 | color: blue; 13 | } 14 | 15 | &, &-box { 16 | color: yellow; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.5.3/styles.css: -------------------------------------------------------------------------------- 1 | @media screen { 2 | .one, 3 | .test { 4 | background-color: #fff; 5 | } 6 | } 7 | @media screen and (min-width: 992px) { 8 | .two, 9 | .test { 10 | color: #777; 11 | } 12 | } 13 | .test { 14 | border-right: 1px solid #000; 15 | } 16 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.7.1/_styles.less: -------------------------------------------------------------------------------- 1 | .screen(@min, @max, @ruleset) { 2 | @media (min-width: @min) and (max-width: (@max - 1)) { 3 | @ruleset(); 4 | } 5 | } 6 | 7 | .class { 8 | background-color: #000; 9 | 10 | .screen(768px, 1200px, { 11 | background-color: #fff; 12 | }); 13 | } -------------------------------------------------------------------------------- /examples/chapter_1/1.4.3/less/_styles.less: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f5f5f5; 3 | color: #777; 4 | } 5 | 6 | h1 { 7 | color: #000; 8 | line-height: 1.25; 9 | font-size: 3rem; 10 | margin-top: 0; 11 | margin-bottom: .5em; 12 | } 13 | 14 | p { 15 | margin-top: 0; 16 | margin-bottom: 0; 17 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.6/_styles.less: -------------------------------------------------------------------------------- 1 | ul, li { 2 | border-top: 2px dotted #366; 3 | 4 | & + & { 5 | border-top: 0; 6 | } 7 | } 8 | 9 | 10 | /* 11 | * Test 12 | */ 13 | 14 | ul, li { 15 | border-top: 2px dotted #366; 16 | 17 | & + & + & { 18 | border-top: 0; 19 | } 20 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.5.3/_styles.less: -------------------------------------------------------------------------------- 1 | @media screen { 2 | .one { 3 | background-color: #fff; 4 | } 5 | 6 | @media (min-width: 992px) { 7 | .two { 8 | color: #777; 9 | } 10 | } 11 | } 12 | 13 | .test { 14 | &:extend(.one, .two); 15 | border-right: 1px solid #000; 16 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.2.2/_styles.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | @color-prefix: color; 3 | 4 | @color-grey: #fafafa; 5 | @color-red: #ffebee; 6 | 7 | 8 | 9 | // Code 10 | .grey { 11 | background-color: e("@{@{color-prefix}-grey}"); 12 | } 13 | 14 | .red { 15 | background-color: e("@{@{color-prefix}-red}"); 16 | } -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.3/test.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.1/styles/less/_styles.less: -------------------------------------------------------------------------------- 1 | @logo-path: "../../images/avatar.jpg"; 2 | 3 | .logo { 4 | @logo-width: image-width(@logo-path); 5 | @logo-height: image-height(@logo-path); 6 | @logo-size: image-size(@logo-path); 7 | 8 | content: "@{logo-size} [@{logo-width} x @{logo-height}]"; 9 | } 10 | -------------------------------------------------------------------------------- /examples/chapter_1/1.4.4/styles.css: -------------------------------------------------------------------------------- 1 | .global-header { 2 | position: relative; 3 | background-color: #181e21; 4 | color: #ffffff; 5 | } 6 | .global-header h1 { 7 | font-size: 44px; 8 | line-height: 50px; 9 | } 10 | .global-header h1 small { 11 | font-size: 24px; 12 | line-height: 36px; 13 | } 14 | /*# sourceMappingURL=styles.map */ -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.5.2/_styles.less: -------------------------------------------------------------------------------- 1 | @media screen { 2 | .one { 3 | &:extend(.three, .two); 4 | background-color: #fff; 5 | } 6 | 7 | @media (min-width: 992px) { 8 | .two { 9 | &:extend(.one); 10 | color: #777; 11 | } 12 | } 13 | } 14 | 15 | .three { 16 | border-right: 1px solid #000; 17 | } -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.3.2/styles/less/components/_styles.less: -------------------------------------------------------------------------------- 1 | @logo-path: "../../../images/avatar.jpg"; 2 | 3 | .logo { 4 | @logo-width: image-width(@logo-path); 5 | @logo-height: image-height(@logo-path); 6 | @logo-size: image-size(@logo-path); 7 | 8 | content: "@{logo-size} [@{logo-width} x @{logo-height}]"; 9 | } 10 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.3/_styles.less: -------------------------------------------------------------------------------- 1 | .transition(@function: ease, @duration: .3s, @property: all) { 2 | transition-timing-function: @function; 3 | transition-duration: @duration; 4 | transition-property: @property; 5 | } 6 | 7 | .block { 8 | .transition(linear); 9 | } 10 | 11 | .link { 12 | .transition(linear, .5s); 13 | } -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.2.1/styles.css: -------------------------------------------------------------------------------- 1 | .block { 2 | background-image: url("../images/header-bg.png"); 3 | } 4 | 5 | @media only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) { 6 | .block { 7 | background-image: url("../images/header-bg@2x.png"); 8 | background-size: 18px 18px; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.7.2/_styles.less: -------------------------------------------------------------------------------- 1 | @variable: global; 2 | @detached-ruleset: { 3 | // will use global variable, because it is accessible 4 | // from detached-ruleset definition 5 | variable: @variable; 6 | }; 7 | 8 | selector { 9 | @detached-ruleset(); 10 | @variable: value; // variable defined in caller - will be ignored 11 | } -------------------------------------------------------------------------------- /examples/chapter_2/homework/less/_grid.less: -------------------------------------------------------------------------------- 1 | // Контейнер для содержимого сайта 2 | .container { 3 | &:extend(.clearfix all); 4 | position: relative; 5 | margin-left: auto; 6 | margin-right: auto; 7 | 8 | @media (min-width: 768px) { 9 | width: 750px; 10 | } 11 | 12 | @media (min-width: 992px) { 13 | width: 970px; 14 | } 15 | } -------------------------------------------------------------------------------- /examples/chapter_3/homework/less/_grid.less: -------------------------------------------------------------------------------- 1 | // Контейнер для содержимого сайта 2 | .container { 3 | &:extend(.clearfix all); 4 | position: relative; 5 | margin-left: auto; 6 | margin-right: auto; 7 | 8 | @media (min-width: 768px) { 9 | width: 750px; 10 | } 11 | 12 | @media (min-width: 992px) { 13 | width: 970px; 14 | } 15 | } -------------------------------------------------------------------------------- /examples/chapter_5/examples/5.2.1/styles.less: -------------------------------------------------------------------------------- 1 | @column-name: col; // Префикс класса сетки 2 | @column-count: 4; // Количество классов 3 | 4 | .generate-column(@i: 1) when (@i =< @column-count) { 5 | .@{column-name}-@{i} { 6 | width: @i * (100% / @column-count); 7 | } 8 | 9 | .generate-column(@i + 1); 10 | } 11 | 12 | .generate-column(); 13 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.1/basic.css: -------------------------------------------------------------------------------- 1 | /* Это стандартный однострочный комментарий для CSS */ 2 | .test-1 { 3 | color: #000; 4 | } 5 | /* 6 | А это стандартный блочный комментарий для CSS. 7 | При необходимости можно использовать и его. 8 | */ 9 | .test-2 { 10 | background-color: #fff; 11 | } 12 | .test-3 { 13 | border: 1px solid #ddd; 14 | } 15 | -------------------------------------------------------------------------------- /examples/chapter_1/test.css: -------------------------------------------------------------------------------- 1 | .area { 2 | margin-right: auto; 3 | margin-left: auto; 4 | } 5 | .area:before, 6 | .area:after { 7 | display: table; 8 | content: " "; 9 | } 10 | .area:after { 11 | clear: both; 12 | } 13 | @media (min-width: 768px) { 14 | .area { 15 | width: 750px; 16 | padding-right: 15px; 17 | padding-left: 15px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/chapter_1/1.4.4/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /examples/chapter_1/_test.less: -------------------------------------------------------------------------------- 1 | .area { 2 | margin-right: auto; 3 | margin-left: auto; 4 | } 5 | 6 | .area:before, 7 | .area:after { 8 | display: table; 9 | content: " "; 10 | } 11 | 12 | .area:after { 13 | clear: both; 14 | } 15 | 16 | @media (min-width: 768px) { 17 | .area { 18 | width: 750px; 19 | padding-right: 15px; 20 | padding-left: 15px; 21 | } 22 | } -------------------------------------------------------------------------------- /chapter_5/intro.md: -------------------------------------------------------------------------------- 1 | # Глава 5. Инструкции (операторы) 2 | 3 | Препроцессор Less включает несколько инструкций (операторов), называемых также *управляющими инструкциями (конструкциями)*. Набор инструкций тривиален и включает в себя только классический `if` и `while`, причём со своим синтаксисом, назначением и большим количеством ограничений. 4 | 5 | > Категоричность — признак ограниченности. 6 | > 7 | > Конфуций 8 | -------------------------------------------------------------------------------- /examples/chapter_1/1.4.4/_styles.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | @header-background: #181e21; 3 | @header-color: #fff; 4 | 5 | .global-header { 6 | position: relative; 7 | background-color: @header-background; 8 | color: @header-color; 9 | 10 | h1 { 11 | font-size: 44px; 12 | line-height: 50px; 13 | 14 | small { 15 | font-size: 24px; 16 | line-height: 36px; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.1/_basic.less: -------------------------------------------------------------------------------- 1 | /* Это стандартный однострочный комментарий для CSS */ 2 | 3 | .test-1 { 4 | color: #000; 5 | } 6 | 7 | /* 8 | А это стандартный блочный комментарий для CSS. 9 | При необходимости можно использовать и его. 10 | */ 11 | 12 | .test-2 { 13 | background-color: #fff; 14 | } 15 | 16 | // Это препроцессорный однострочный комментарий 17 | 18 | .test-3 { 19 | border: 1px solid #ddd; 20 | } -------------------------------------------------------------------------------- /examples/chapter_6/examples/6.1.4/styles.less: -------------------------------------------------------------------------------- 1 | .rotate3d(...) { 2 | @js: ~`(function(e) { 3 | return e = e || "0, 0, 0, 0", e = e.replace(/,\s*\d+$/, function(e) { 4 | return e + "deg" 5 | }) 6 | })((function() { 7 | var e = "@{arguments}"; 8 | return e = e.replace(/^\[|\]$/g, "") 9 | })())`; 10 | transform: rotate3d(@js); 11 | } 12 | 13 | .test-js { 14 | .rotate3d(1, 0, 0, 50); 15 | .rotate3d(); 16 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.1.1/_styles.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | @body-background: #f5f5f5; 3 | @body-font-size: 14px; 4 | 5 | // Code 6 | body { 7 | background-color: @body-background; 8 | font-size: @body-font-size; 9 | } 10 | 11 | .block { 12 | @block-color: #333; 13 | @block-font-size: 28px; 14 | 15 | font-size: @block-font-size; 16 | color: @block-color; 17 | } 18 | 19 | .element { 20 | font-size: @block-font-size; 21 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.6/styles.css: -------------------------------------------------------------------------------- 1 | ul, 2 | li { 3 | border-top: 2px dotted #366; 4 | } 5 | ul + ul, 6 | ul + li, 7 | li + ul, 8 | li + li { 9 | border-top: 0; 10 | } 11 | /* 12 | * Test 13 | */ 14 | ul, 15 | li { 16 | border-top: 2px dotted #366; 17 | } 18 | ul + ul + ul, 19 | ul + ul + li, 20 | ul + li + ul, 21 | ul + li + li, 22 | li + ul + ul, 23 | li + ul + li, 24 | li + li + ul, 25 | li + li + li { 26 | border-top: 0; 27 | } 28 | -------------------------------------------------------------------------------- /examples/chapter_4/homework/task_1/styles.less: -------------------------------------------------------------------------------- 1 | .mixin(@a, @b, @c) { 2 | @sqrt: sqrt(@a); 3 | @cos: cos(@b); 4 | @max: max(@a, @b, @c); 5 | @pow: pow(@c, 5); 6 | @return: (@sqrt + @cos + @max) / @pow; 7 | } 8 | 9 | .test { 10 | .mixin(9, pi(), 1); 11 | content: @return; 12 | } 13 | 14 | // sqrt(9) = 3 15 | // cos(pi()) = -1 16 | // max(9, pi, 1) = 9 17 | // pow(1, 5) = 1 18 | // return = (3 + -1 + 9) / 1 = 11 / 1 = 11 19 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.6/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | * No options 3 | */ 4 | .yahoo { 5 | color: #400191; 6 | } 7 | .canonium { 8 | color: #53599a; 9 | } 10 | /* 11 | * (once) 12 | */ 13 | .yandex { 14 | color: #ffcc00; 15 | } 16 | .canonium { 17 | color: #53599a; 18 | } 19 | /* 20 | * (multiple) 21 | */ 22 | .duckduckgo { 23 | color: #de5833; 24 | } 25 | .canonium { 26 | color: #53599a; 27 | } 28 | .duckduckgo { 29 | color: #de5833; 30 | } 31 | -------------------------------------------------------------------------------- /examples/chapter_3/homework/less/_mixins.less: -------------------------------------------------------------------------------- 1 | // Изменение оформления кнопки 2 | .button-style(@_bg, @_color, @_hover-bg, @_hover-color) { 3 | background-color: @_bg; 4 | color: @_color; 5 | 6 | &:focus, 7 | &:hover, 8 | &.active { 9 | background-color: @_hover-bg; 10 | color: @_hover-color; 11 | } 12 | } 13 | 14 | // Изменение размеров кнопки 15 | .button-size(@_font, @_padding) { 16 | font-size: @_font; 17 | padding: @_padding; 18 | } -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.5.4/_styles.less: -------------------------------------------------------------------------------- 1 | .mixin(@color) { 2 | color: @color; 3 | } 4 | 5 | .mixin(@color, @bg) { 6 | color: @color; 7 | background-color: @bg; 8 | } 9 | 10 | .mixin(@color, @bg, @border-color) { 11 | color: @color; 12 | background-color: @bg; 13 | border: 1px solid @border-color; 14 | } 15 | 16 | .mixin(@bg, @color) { 17 | color: @color; 18 | background-color: @bg; 19 | } 20 | 21 | .class { 22 | .mixin(#333, #f5f5f5); 23 | } -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.2.1/styles.less: -------------------------------------------------------------------------------- 1 | .bg(@path, @width, @height) { 2 | background-image: url(@path); 3 | 4 | @media only screen and (min-resolution: (1.5 * 96dpi)), only screen and (min-resolution: (1.5 * 1dppx)) { 5 | @retina: replace(@path, "(\.[0-9a-z]+)$", "@2x$1", "i"); 6 | background-image: url(@retina); 7 | background-size: @width @height; 8 | } 9 | } 10 | 11 | .block { 12 | .bg("../images/header-bg.png", 18px, 18px); 13 | } 14 | -------------------------------------------------------------------------------- /examples/chapter_5/examples/5.1.1/styles.less: -------------------------------------------------------------------------------- 1 | .padding(@t: none, @r: none, @b: none, @l: none) { 2 | & when not (@t = none) { padding+_: @t; } 3 | & when not (@r = none) { padding+_: @r; } 4 | & when not (@b = none) { padding+_: @b; } 5 | & when not (@l = none) { padding+_: @l; } 6 | } 7 | 8 | .test-one { .padding(10px) } 9 | .test-two { .padding(10px, 5px) } 10 | .test-three { .padding(10px, 5px, 15px) } 11 | .test-four { .padding(10px, 5px, 15px, 20px) } 12 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.2.2/styles.css: -------------------------------------------------------------------------------- 1 | .global-header { 2 | background-color: #f5f5f5; 3 | color: #443d3d; 4 | border-bottom: 1px solid #ddd; 5 | } 6 | .global-header h1 { 7 | margin-top: 0; 8 | margin-bottom: 0; 9 | font-size: 4rem; 10 | } 11 | .global-header h1 small { 12 | font-size: 2rem; 13 | } 14 | .global-header .header-actions { 15 | background-color: #fff; 16 | padding-top: 10px; 17 | padding-bottom: 10px; 18 | text-align: center; 19 | } 20 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.4.5/_styles.less: -------------------------------------------------------------------------------- 1 | .mixin(@color) { 2 | color: @color; 3 | } 4 | 5 | .mixin(@color, @bg) { 6 | color: @color; 7 | background-color: @bg; 8 | } 9 | 10 | .mixin(@color, @bg, @border-color) { 11 | color: @color; 12 | background-color: @bg; 13 | border: 1px solid @border-color; 14 | } 15 | 16 | .test-1 { 17 | .mixin(#333); 18 | } 19 | 20 | .test-2 { 21 | .mixin(#333, #fff); 22 | } 23 | 24 | .test-3 { 25 | .mixin(#333, #fff, #ddd); 26 | } -------------------------------------------------------------------------------- /examples/chapter_5/homework/styles.less: -------------------------------------------------------------------------------- 1 | // Имена классов 2 | @listNames: black, red, purple, green, blue; 3 | // Цвет 4 | @listColors: #000000, #ff0000, #800080, #008000, #0000ff; 5 | 6 | .generate-class(@index: 1) when (@index <= length(@listNames)) { 7 | @name: extract(@listNames, @index); 8 | @color: extract(@listColors, @index); 9 | 10 | .color-@{name} { 11 | color: @color; 12 | } 13 | 14 | .generate-class(@index + 1); 15 | } 16 | 17 | .generate-class(); 18 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.2.2/_styles.less: -------------------------------------------------------------------------------- 1 | .global-header { 2 | background-color: #f5f5f5; 3 | color: #443d3d; 4 | border-bottom: 1px solid #ddd; 5 | 6 | h1 { 7 | margin-top: 0; 8 | margin-bottom: 0; 9 | font-size: 4rem; 10 | 11 | small { 12 | font-size: 2rem; 13 | } 14 | } 15 | 16 | .header-actions { 17 | background-color: #fff; 18 | padding-top: 10px; 19 | padding-bottom: 10px; 20 | text-align: center; 21 | } 22 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.2.1/styles.css: -------------------------------------------------------------------------------- 1 | .global-header { 2 | background-color: #f5f5f5; 3 | color: #443d3d; 4 | border-bottom: 1px solid #ddd; 5 | } 6 | 7 | .global-header h1 { 8 | margin-top: 0; 9 | margin-bottom: 0; 10 | font-size: 4rem; 11 | } 12 | 13 | .global-header h1 small { 14 | font-size: 2rem; 15 | } 16 | 17 | .global-header .header-actions { 18 | background-color: #fff; 19 | padding-top: 10px; 20 | padding-bottom: 10px; 21 | text-align: center; 22 | } -------------------------------------------------------------------------------- /examples/chapter_2/homework/less/_typography.less: -------------------------------------------------------------------------------- 1 | // Заголовки 2 | h1, 3 | h2, 4 | h3, 5 | h4, 6 | h5, 7 | h6 { 8 | margin-top: 0; 9 | margin-bottom: 0; 10 | } 11 | 12 | h1 { 13 | font-weight: 300; 14 | line-height: 1.25; 15 | font-size: 3.2rem; 16 | } 17 | 18 | 19 | 20 | 21 | //Списки 22 | ul { 23 | margin: 0; 24 | padding: 0; 25 | list-style: none; 26 | } 27 | 28 | 29 | 30 | // Изображения 31 | img { 32 | display: block; 33 | max-width: 100%; 34 | height: auto; 35 | } -------------------------------------------------------------------------------- /chapter_1/intro.md: -------------------------------------------------------------------------------- 1 | # Глава 1. Основы 2 | 3 | Прежде чем начинать использовать технологии, хорошо было бы понять, что они из себя представляют и зачем вообще могут пригодиться. В этой главе я расскажу о том, что такое препроцессор и CSS-препроцессор, приведу несколько популярных проектов в этой области и постараюсь передать их суть. Наконец, вы узнаете о препроцессоре Less, о котором и написана эта книга. 4 | 5 | > Какой богатый внутренний мир. Ну-ка дай-ка взглянуть. 6 | > 7 | > Gearbox Software — Duke Nukem Forever 8 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo symbol & 6 | 7 | 8 | 9 | 10 | 11 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptates sit corporis quia, eaque laboriosam. Optio quas nisi, itaque enim nemo, reiciendis vel eos ipsa, perspiciatis voluptate consectetur illo, labore quia?

12 | 13 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.6.6/_styles.less: -------------------------------------------------------------------------------- 1 | /* 2 | * No options 3 | */ 4 | 5 | @import "import/_yahoo"; 6 | 7 | .canonium { 8 | color: #53599a; 9 | } 10 | 11 | @import "import/_yahoo"; 12 | 13 | /* 14 | * (once) 15 | */ 16 | @import (once) "import/_yandex"; 17 | 18 | .canonium { 19 | color: #53599a; 20 | } 21 | 22 | @import (once) "import/_yandex"; 23 | 24 | /* 25 | * (multiple) 26 | */ 27 | @import (multiple) "import/_duckduckgo"; 28 | 29 | .canonium { 30 | color: #53599a; 31 | } 32 | 33 | @import (multiple) "import/_duckduckgo"; -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.2.1/styles/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'FontAwesome'; 3 | src: url('../fonts/fontawesome-webfont.eot?v=4.3.0'); 4 | src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg'); 5 | font-weight: normal; 6 | font-style: normal; 7 | } 8 | -------------------------------------------------------------------------------- /chapter_6/intro.md: -------------------------------------------------------------------------------- 1 | # Глава 6. JavaScript в Less 2 | 3 | Этой главой заканчивается основная, фундаментальная часть книги, рассказывающая о возможностях CSS-препроцессора Less. Финал должен быть красивым, и обеспечить его может только недокументированная возможность исполнения JavaScript-кода в less-файлах. 4 | 5 | Из этой главы вы узнаете, как использовать JavaScript-код в Less, манипулировать введенными данными, обрабатывать и возвращать их. 6 | 7 | > Ваши дома — коробки, а ваши машины — это коробки на колесах. На работу в коробке и в коробке домой. 8 | > 9 | > Посылка (The Box) 10 | -------------------------------------------------------------------------------- /chapter_3/intro.md: -------------------------------------------------------------------------------- 1 | # Глава 3. Переменные и примеси 2 | 3 | Во всех языках программирования существуют переменные и функции, которые позволяют делать код чистым и переиспользуемым. Как мы все знаем, CSS, по сути своей, не является языком программирования в прямом смысле этого выражения. Но, с помощью препроцессоров, можно попытаться исправить это положение. 4 | 5 | Из этой главы вы узнаете, как использовать переменные и примеси, правильно давать им имена, а также некоторые особенности и тонкости их применения в реальных проектах. 6 | 7 | > Может, звучит глупо, но именно глупости запоминаются лучше всего. 8 | > 9 | > Вверх (Up) -------------------------------------------------------------------------------- /examples/chapter_1/1.4.1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo Less 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Title

16 | 17 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure voluptate vel, maxime enim porro modi repellat doloribus ab ex tempora accusamus eius quam omnis, impedit ipsam facilis nulla repellendus. Maiores!

18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/chapter_1/1.4.2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo Less 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Title

16 | 17 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure voluptate vel, maxime enim porro modi repellat doloribus ab ex tempora accusamus eius quam omnis, impedit ipsam facilis nulla repellendus. Maiores!

18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.3/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Before 3 | */ 4 | .item-card { 5 | background-color: #f5f5f5; 6 | border-image: url("images/bg-image.png") 30 round round; 7 | } 8 | /* 9 | * After 10 | */ 11 | .item-card { 12 | background-color: #f5f5f5; 13 | border-image: url("images/bg-image.png") 30 round round; 14 | } 15 | .ie7 .item-card { 16 | border: 1px solid #a31515; 17 | } 18 | /* 19 | * Attention 20 | */ 21 | .item-card { 22 | background-color: #f5f5f5; 23 | border-image: url("images/bg-image.png") 30 round round; 24 | } 25 | .ie7.item-card { 26 | border: 1px solid #a31515; 27 | } 28 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.3/_styles.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Before 3 | */ 4 | .item-card { 5 | background-color: #f5f5f5; 6 | border-image: url("images/bg-image.png") 30 round round; 7 | } 8 | 9 | /* 10 | * After 11 | */ 12 | .item-card { 13 | background-color: #f5f5f5; 14 | border-image: url("images/bg-image.png") 30 round round; 15 | 16 | .ie7 & { 17 | border: 1px solid #a31515; 18 | } 19 | } 20 | 21 | 22 | /* 23 | * Attention 24 | */ 25 | .item-card { 26 | background-color: #f5f5f5; 27 | border-image: url("images/bg-image.png") 30 round round; 28 | 29 | .ie7& { 30 | border: 1px solid #a31515; 31 | } 32 | } -------------------------------------------------------------------------------- /chapter_4/intro.md: -------------------------------------------------------------------------------- 1 | # Глава 4. Операции со свойствами и встроенные функции 2 | 3 | Для удобства пользователей препроцессора Less его разработчики добавили некоторые встроенные функции. 4 | 5 | В этой главе мы поговорим о возможности слияния свойств, которое может пригодиться при наличии одинаковых свойств в двух селекторах (примесях), встроенных функциях для работы со строками, списками (массивами), изображениями и типами данных. А также затронем тему манипуляции цветами и поговорим о наличии всевозможных математических функциях, которые зачем-то могут пригодиться в CSS. 6 | 7 | > Терпимость — это когда прощают чужие ошибки; такт — когда не замечают их. 8 | > 9 | > Артур Шницлер 10 | -------------------------------------------------------------------------------- /examples/chapter_2/homework/less/_core.less: -------------------------------------------------------------------------------- 1 | // Изменение блочной модели 2 | * { 3 | &:before, 4 | &:after { 5 | box-sizing: border-box; 6 | } 7 | } 8 | 9 | // Установка базового размера шрифта 10 | // для удобного расчета REM единиц измерения 11 | html { 12 | font-size: 10px; 13 | } 14 | 15 | // Определение типографики 16 | body { 17 | font-size: 14px; 18 | line-height: 20px; 19 | font-family: Lucida Grande, Arial, tahoma, verdana, sans-serif; 20 | font-weight: normal; 21 | } 22 | 23 | // Очищение потока 24 | .clearfix { 25 | &:before, 26 | &:after { 27 | content: " "; 28 | display: table; 29 | } 30 | 31 | &:after { 32 | clear: both; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/chapter_3/homework/less/_core.less: -------------------------------------------------------------------------------- 1 | // Изменение блочной модели 2 | * { 3 | &:before, 4 | &:after { 5 | box-sizing: border-box; 6 | } 7 | } 8 | 9 | // Установка базового размера шрифта 10 | // для удобного расчета REM единиц измерения 11 | html { 12 | font-size: 10px; 13 | } 14 | 15 | // Определение типографики 16 | body { 17 | font-size: 14px; 18 | line-height: 20px; 19 | font-family: Lucida Grande, Arial, tahoma, verdana, sans-serif; 20 | font-weight: normal; 21 | } 22 | 23 | // Очищение потока 24 | .clearfix { 25 | &:before, 26 | &:after { 27 | content: " "; 28 | display: table; 29 | } 30 | 31 | &:after { 32 | clear: both; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.2.2/styles.css: -------------------------------------------------------------------------------- 1 | .col-xs-1 { 2 | width: 25%; 3 | } 4 | .col-sm-1 { 5 | width: 25%; 6 | } 7 | .col-md-1 { 8 | width: 25%; 9 | } 10 | .col-lg-1 { 11 | width: 25%; 12 | } 13 | .col-xs-2 { 14 | width: 50%; 15 | } 16 | .col-sm-2 { 17 | width: 50%; 18 | } 19 | .col-md-2 { 20 | width: 50%; 21 | } 22 | .col-lg-2 { 23 | width: 50%; 24 | } 25 | .col-xs-3 { 26 | width: 75%; 27 | } 28 | .col-sm-3 { 29 | width: 75%; 30 | } 31 | .col-md-3 { 32 | width: 75%; 33 | } 34 | .col-lg-3 { 35 | width: 75%; 36 | } 37 | .col-xs-4 { 38 | width: 100%; 39 | } 40 | .col-sm-4 { 41 | width: 100%; 42 | } 43 | .col-md-4 { 44 | width: 100%; 45 | } 46 | .col-lg-4 { 47 | width: 100%; 48 | } 49 | -------------------------------------------------------------------------------- /examples/chapter_5/examples/5.2.2/styles.css: -------------------------------------------------------------------------------- 1 | .col-xs-1 { 2 | width: 25%; 3 | } 4 | .col-sm-1 { 5 | width: 25%; 6 | } 7 | .col-md-1 { 8 | width: 25%; 9 | } 10 | .col-lg-1 { 11 | width: 25%; 12 | } 13 | .col-xs-2 { 14 | width: 50%; 15 | } 16 | .col-sm-2 { 17 | width: 50%; 18 | } 19 | .col-md-2 { 20 | width: 50%; 21 | } 22 | .col-lg-2 { 23 | width: 50%; 24 | } 25 | .col-xs-3 { 26 | width: 75%; 27 | } 28 | .col-sm-3 { 29 | width: 75%; 30 | } 31 | .col-md-3 { 32 | width: 75%; 33 | } 34 | .col-lg-3 { 35 | width: 75%; 36 | } 37 | .col-xs-4 { 38 | width: 100%; 39 | } 40 | .col-sm-4 { 41 | width: 100%; 42 | } 43 | .col-md-4 { 44 | width: 100%; 45 | } 46 | .col-lg-4 { 47 | width: 100%; 48 | } 49 | -------------------------------------------------------------------------------- /chapter_2/intro.md: -------------------------------------------------------------------------------- 1 | # Глава 2. Работа с селекторами, медиа-запросами и файлами 2 | 3 | Многие статьи начинаются со слов об удобном использовании переменных, примесей и прочих радостях. Я же начну свой рассказ о том, как же хорошо стало работать с селекторами, медиа-запросами и файлами. Мне кажется, что это наиболее важный инструментарий, который предлагает нам препроцессор. Да, работать с переменными одно удовольствие, но с селекторами приходится работать куда чаще. 4 | 5 | В этой главе я расскажу о комментариях, вложенных селекторах, работе с файлами, группировке селекторов и многих других интересных вещах. 6 | 7 | > Если немножко подождать, все само упадёт тебе в лапы. 8 | > 9 | > Twentieth Century Fox — Гарфилд (Garfield) 10 | -------------------------------------------------------------------------------- /examples/chapter_1/1.4.3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo Less 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 |

Title

20 | 21 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure voluptate vel, maxime enim porro modi repellat doloribus ab ex tempora accusamus eius quam omnis, impedit ipsam facilis nulla repellendus. Maiores!

22 | 23 | 24 | -------------------------------------------------------------------------------- /chapter_0/audience.md: -------------------------------------------------------------------------------- 1 | # Целевая аудитория 2 | 3 | Я предполагаю, что читатель обладает знанием HTML, CSS и имеет базовое представление о JavaScript. Помимо этого, потребуется умение открытия консоли и воспроизведения строк, приведённых в этой книге. Также приветствуется представление о системах сборки наподобие Grunt, Gulp, Brunch или Broccoli. 4 | 5 | Независимо от того, как давно вы занимаетесь веб-разработкой и какой у вас за плечами багаж знаний, эта книга поможет понять, почему так важно использование CSS-препроцессоров и почему Less отлично подходит для того, чтобы стать вашим первым CSS-препроцессором. 6 | 7 | Людям, которые привыкли к сухому изложению текста, скучным пересказам документации и отсутствию шуток — книга категорически запрещается к прочтению. Вот такие вот дела. 8 | -------------------------------------------------------------------------------- /examples/chapter_2/homework/less/_gallery.less: -------------------------------------------------------------------------------- 1 | // Контейнер для галереи 2 | .gallery-slider { 3 | background-color: #bdc3c7; 4 | padding-top: 35px; 5 | padding-bottom: 35px; 6 | } 7 | 8 | // Список изображений 9 | .gallery-list { 10 | &:extend(.clearfix all); 11 | 12 | li { 13 | @media (min-width: 540px) { 14 | width: 50%; 15 | float: left; 16 | } 17 | 18 | @media (min-width: 768px) { 19 | width: 33.33333%; 20 | } 21 | 22 | @media (min-width: 992px) { 23 | width: 20%; 24 | } 25 | } 26 | 27 | a { 28 | display: block; 29 | margin: 10px; 30 | 31 | &:hover, 32 | &:focus { 33 | opacity: .5; 34 | } 35 | } 36 | 37 | img { 38 | margin-left: auto; 39 | margin-right: auto; 40 | } 41 | } -------------------------------------------------------------------------------- /chapter_5/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание 2 | 3 | В этом домашнем задании вам предстоит написать код для генерации вспомогательных классов на основе предоставляемых данных в виде двух списков. 4 | 5 | Входные данные будут такими: 6 | 7 | ```less 8 | // Имена классов 9 | @listNames: black, red, purple, green, blue; 10 | // Цвет 11 | @listColors: #000000, #ff0000, #800080, #008000, #0000ff; 12 | ``` 13 | 14 | Индексы двух списков совпадают. Так, например, класс `black` имеет цвет `#000000`, а `purple` — `#800080`. 15 | 16 | Результат должен совпадать с вручную написанным CSS-кодом: 17 | 18 | ```less 19 | .color-black { color: #000000; } 20 | .color-red { color: #ff0000; } 21 | ... 22 | .color-blue { color: #0000ff; } 23 | ``` 24 | 25 | > **Замечание** 26 | > 27 | > Результат отформатирован вручную для наглядности. 28 | -------------------------------------------------------------------------------- /examples/chapter_3/examples/3.2.1/styles/_styles.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | @icon-prefix: icon; 3 | @icon-font-name: fontawesome-webfont; 4 | @icon-font-path: "../fonts"; 5 | @icon-glyph-book: book; 6 | 7 | // Loading font 8 | @font-face { 9 | font-family: 'FontAwesome'; 10 | src: url('@{icon-font-path}/@{icon-font-name}.eot?v=4.3.0'); 11 | src: url('@{icon-font-path}/@{icon-font-name}.eot?#iefix&v=4.3.0') format('embedded-opentype'), 12 | url('@{icon-font-path}/@{icon-font-name}.woff2?v=4.3.0') format('woff2'), 13 | url('@{icon-font-path}/@{icon-font-name}.woff?v=4.3.0') format('woff'), 14 | url('@{icon-font-path}/@{icon-font-name}.ttf?v=4.3.0') format('truetype'), 15 | url('@{icon-font-path}/@{icon-font-name}.svg?v=4.3.0#fontawesomeregular') format('svg'); 16 | font-weight: normal; 17 | font-style: normal; 18 | } -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.4/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Before 3 | */ 4 | .button { 5 | background-color: #ddd; 6 | color: #000; 7 | } 8 | .button-add { 9 | background-color: green; 10 | color: #fff; 11 | } 12 | .button-remove { 13 | background-color: red; 14 | color: #fff; 15 | } 16 | /* 17 | * After 18 | */ 19 | .button { 20 | background-color: #ddd; 21 | color: #000; 22 | } 23 | .button-add { 24 | background-color: green; 25 | color: #fff; 26 | } 27 | .button-remove { 28 | background-color: red; 29 | color: #fff; 30 | } 31 | /* 32 | * Optimization 33 | */ 34 | .button { 35 | background-color: #ddd; 36 | color: #000; 37 | } 38 | .button-add, 39 | .button-remove { 40 | color: #fff; 41 | } 42 | .button-add { 43 | background-color: green; 44 | } 45 | .button-remove { 46 | background-color: red; 47 | } 48 | -------------------------------------------------------------------------------- /examples/chapter_2/examples/2.3.4/_styles.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Before 3 | */ 4 | .button { 5 | background-color: #ddd; 6 | color: #000; 7 | } 8 | 9 | .button-add { 10 | background-color: green; 11 | color: #fff; 12 | } 13 | 14 | .button-remove { 15 | background-color: red; 16 | color: #fff; 17 | } 18 | 19 | /* 20 | * After 21 | */ 22 | .button { 23 | background-color: #ddd; 24 | color: #000; 25 | 26 | &-add { 27 | background-color: green; 28 | color: #fff; 29 | } 30 | 31 | &-remove { 32 | background-color: red; 33 | color: #fff; 34 | } 35 | } 36 | 37 | /* 38 | * Optimization 39 | */ 40 | .button { 41 | background-color: #ddd; 42 | color: #000; 43 | 44 | &-add, 45 | &-remove { 46 | color: #fff; 47 | } 48 | 49 | &-add { background-color: green; } 50 | &-remove { background-color: red; } 51 | } -------------------------------------------------------------------------------- /examples/chapter_4/examples/4.2.2/styles.less: -------------------------------------------------------------------------------- 1 | @column-name: col; 2 | @column-count: 4; 3 | @column-prefix: xs, sm, md, lg; 4 | 5 | // Генератор селекторов 6 | .generate-class(@indexCount, @indexPrefix: 1) when (@indexPrefix =< length(@column-prefix)) { 7 | 8 | // Получаем элемент списка 9 | @prefix: extract(@column-prefix, @indexPrefix); 10 | 11 | // Формируем селектор 12 | .@{column-name}-@{prefix}-@{indexCount} { 13 | width: @indexCount * (100% / @column-count); 14 | } 15 | 16 | // Порождаем следующую итерацию 17 | .generate-class(@indexCount, @indexPrefix + 1); 18 | } 19 | 20 | // Генератор сетки 21 | .make-grid(@indexCount: 1) when (@indexCount =< @column-count) { 22 | 23 | // Вызываем генератор селекторов 24 | .generate-class(@indexCount); 25 | 26 | // Порождаем следующую итерацию 27 | .make-grid(@indexCount + 1); 28 | 29 | } 30 | 31 | // Вызываем генератор сетки 32 | .make-grid(); -------------------------------------------------------------------------------- /examples/chapter_5/examples/5.2.2/styles.less: -------------------------------------------------------------------------------- 1 | // Настройки 2 | @column-name: col; 3 | @column-count: 4; 4 | @column-prefix: xs, sm, md, lg; 5 | 6 | // Генератор селекторов 7 | .generate-class(@indexCount, @indexPrefix: 1) when (@indexPrefix =< length(@column-prefix)) { 8 | 9 | // Получаем элемент списка 10 | @prefix: extract(@column-prefix, @indexPrefix); 11 | 12 | // Формируем селектор 13 | .@{column-name}-@{prefix}-@{indexCount} { 14 | width: @indexCount * (100% / @column-count); 15 | } 16 | 17 | // Порождаем следующую итерацию 18 | .generate-class(@indexCount, @indexPrefix + 1); 19 | } 20 | 21 | // Генератор сетки 22 | .make-grid(@indexCount: 1) when (@indexCount =< @column-count) { 23 | 24 | // Вызываем генератор селекторов 25 | .generate-class(@indexCount); 26 | 27 | // Порождаем следующую итерацию 28 | .make-grid(@indexCount + 1); 29 | 30 | } 31 | 32 | // Вызываем генератор сетки 33 | .make-grid(); 34 | -------------------------------------------------------------------------------- /examples/chapter_3/homework/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Домашнее задание #2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

Состояние по умолчанию

15 | 16 | 17 | 18 | 19 |

Нажатое состояние

20 | 21 | 22 | 23 | 24 |

Различные размеры

25 | 26 | 27 | 28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Помощь в написании книги 2 | 3 | Спасибо, что решили помочь мне. 4 | 5 | ## Pull Requests (PR) 6 | 7 | Я буду очень рад, если кто-то решит помочь мне в написании книги, либо исправит найденные в ней ошибки, опечатки и прочие неточности. Однако, я прошу вас соблюдать некоторые правила: 8 | 9 | * Добавляйте описание к вашему PR. 10 | * Пожалуйста, отправляйте PR в ветку `develop`. 11 | * Не торопитесь и хорошо обдумайте ваше предложение. 12 | * Не переусердствуйте с просторечиями и жаргонами. 13 | * Не забывайте использовать `ё`. 14 | 15 | В случае, если в вашем PR будет отсутствовать описание, то я попрошу объяснить вашу точку зрения. Если же PR будет сделан в ветку `master`, то я оповещу вас о том, что вы не соблюдаете простейшие правила и попрошу исправить найденные ошибки. 16 | 17 | Прочие требования к разметке книги: 18 | 19 | * Везде используйте пробелы. 20 | * Отбивайте заголовки следующим образом: 21 | * H1 и H2 — 4 строки сверху, 1 строка снизу 22 | * H3 — 3 строки сверху, 1 строка снизу 23 | * H4 — 2 строки сверху, 1 строка снизу 24 | * H5 и H6 — 1 строка сверху, 1 строка снизу 25 | * Блок кода должен отбиваться 1 строкой сверху и 1 строкой снизу. 26 | * Указывайте язык в разметке, используемый в примерах. 27 | -------------------------------------------------------------------------------- /examples/chapter_2/homework/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Домашнее задание #1 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

Посмотрите на эти прекрасные картинки с цифрами

15 |
16 |
17 | 18 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /chapter_4/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание 2 | 3 | На этот раз читателю предлагается решить несколько задач для закрепления пройденного материала. 4 | 5 | 6 | 7 | 8 | ## Задача 1. Вычисление значения 9 | 10 | На основе знаний, полученных из главы 3 и 4, необходимо написать примесь, которая возвращает переменную `@result`. Для этого предлагается использовать примесь как функцию. 11 | 12 | В этой функции требуется найти результат следующего математического выражения: 13 | 14 | ![](../images/chapter_4_homework_1.png) 15 | 16 | При решении следует использовать математические функции. 17 | 18 | 19 | 20 | 21 | ## Задача 2. Работа с цветом 22 | 23 | На основе знаний, полученных в этой главе, требуется написать less-файл, в котором: 24 | 25 | * Инициализирована переменная `@color` с любым произвольным цветом. 26 | * Определены переменные `@color-darken` и `@color-light`, значения которых зависят от переменной `@color` следующим образом: 27 | * Значение `@color-dark` является значением переменной `@color`, затемнённым на 25%. 28 | * Значение `@color-light` является значением переменной `@color`, осветлённым на 25%. 29 | * Определён цвет ссылки по умолчанию, как значение переменной `@color-dark`, а цвет при наведении курсора мыши является значением переменной `@color-light`. 30 | 31 | Не волнуйтесь, у вас все получится! Если у вас возникают какие-либо сложности, 32 | то посмотрите решение этого задания в архиве, который прилагается к этой 33 | книге. 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Добро пожаловать в **Путеводитель для новичков по CSS-препроцессору Less**! Эта книга поможет вам разобраться со всеми возможностями, которые предоставляет этот замечательный CSS-препроцессор. Неважно, новичок вы, впервые решивший разобраться с препроцессорами или бородатый веб-разработчик, который повидал на своём веку многие технологии — каждый найдёт что-нибудь интересное для себя. 2 | 3 | 4 | 5 | 6 | ## Необходимые умения: 7 | 8 | Прежде чем вы перейдёте к чтению, я бы хотел рассказать о нескольких основных правилах: 9 | 10 | * У вас установлен [Node.js](https://nodejs.org/). 11 | * Вы умеете пользоваться пакетным менеджером [npm](https://www.npmjs.com/). 12 | * Вы имеете представление о работе с консолью. 13 | * Вы хорошо знаете HTML (HTML5), CSS3 и как-нибудь разбираетесь в JavaScript. 14 | 15 | 16 | 17 | 18 | ## Текущее положение дел 19 | 20 | На текущий момент основная часть книги написана и соответствует реальности. Хотя работа ещё далека от того момента, когда можно сказать «хватит» — книгу уже можно рекомендовать к прочтению. Я стараюсь поддерживать актуальность изложенной в ней информации и пристально слежу за каждым выходом новой версии Less. 21 | 22 | 23 | 24 | 25 | ## Прочее 26 | 27 | Если у вас нет времени на прочтение этой книги, то могу порекомендовать вам пройти два курса проекта HTML Academy: 28 | 29 | * [«Знакомство с LESS»](https://htmlacademy.ru/courses/85) 30 | * [«Примеси в LESS»](https://htmlacademy.ru/courses/125) 31 | 32 | --- 33 | 34 | [www.canonium.com](https://www.canonium.com/) 35 | 36 | [Анонс книги на Canonium](https://www.canonium.com/articles/less-guidebook-for-beginners) 37 | 38 | [Репозиторий на GitHub](https://github.com/mrmlnc/less-guidebook-for-beginners) 39 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | * **2016-06-11** 2 | * **Глава 3. Экранирование.** Исправлено описание функции `e()` и её нежелательное применение в коде ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/e6bd7ed3b9d59f74296d444b37caa76bfd062d70)) 3 | * **Глава 3. Частый случай интерполяции переменных внутри переменных.** Новый раздел, описывающий частный случай интерполяции ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/fd3828b81d20adbcdd33603b191ee3fd2d41fe55)) 4 | * Удалены последние упоминания о io.js ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/fa731cced731913f98da0ae2e9fd89bfc0bb0329)) 5 | 6 | * **2016-04-23** 7 | * **Глава 2. Сшивание (склеивание) селекторов.** Дополнение по примеру ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/527b5548953997b5096d8b96002bd62158f321d1)) 8 | * Почистил текст. Продолжаю отслеживать правильное употребление `е` и `ё`. 9 | 10 | * **2016-04-17** 11 | * **Глава 4. Функция форматирования строки.** Добавлено полное описание функции ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/de3fb2865f7dc9b694518ff3092aa1db6509de72)) 12 | * **Глава 4. Функция замены (Replace).** Добавлено полное описание функции ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/de3fb2865f7dc9b694518ff3092aa1db6509de72)) 13 | 14 | * **2016-04-16** 15 | * **Глава 5. Условные конструкции.** Описание ключевого слова `or` ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/f7a29fe030fbfcdb6328ea9568b5eb248c31a1bf)) 16 | 17 | * **2016-01-09** 18 | * **Глава 6. Обзор возможностей.** Корректное описание результата работы выражения в главе ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/ca9260ee35677f6c054e703850ec7306118837b3)) 19 | 20 | * **2016-01-08** 21 | * **README.** Упоминание о курсе «HTML Academy» ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/4ea28de445a1ac22aba0df71130a00e5725ca6c2)) 22 | * **Глава 3. Специальные параметры и сопоставление шаблонов.** Корректировка строки о PostCSS ([commit](https://github.com/mrmlnc/less-guidebook-for-beginners/commit/599b2c61fca7dc909c89ff2b76a928ebe23fb4f9)) 23 | -------------------------------------------------------------------------------- /examples/chapter_3/homework/less/_buttons.less: -------------------------------------------------------------------------------- 1 | // Общие переменные для всех кнопок 2 | @btn-border-radius: 4px; 3 | 4 | // Переменные стилевого оформления кнопок 5 | @btn-default-bg: #e0e0e0; 6 | @btn-default-color: #333; 7 | @btn-default-hover-bg: #e8e8e8; 8 | @btn-default-hover-color: #333; 9 | 10 | @btn-info-bg: #3b83c0; 11 | @btn-info-color: #fff; 12 | @btn-info-hover-bg: #458ac6; 13 | @btn-info-hover-color: #fff; 14 | 15 | @btn-secondary-bg: #404245; 16 | @btn-secondary-color: #fff; 17 | @btn-secondary-hover-bg: #1b1c1d; 18 | @btn-secondary-hover-color: #fff; 19 | 20 | // Переменные размера кнопок 21 | @btn-font-size: 14px; 22 | @btn-line-height: 20px; 23 | @btn-padding: 6px 12px; 24 | 25 | @btn-size-xs-font-size: 10px; 26 | @btn-size-xs-padding: 2px 4px; 27 | 28 | @btn-size-xl-font-size: 18px; 29 | @btn-size-xl-padding: 10px 16px; 30 | 31 | 32 | 33 | // Основа кнопки 34 | .btn { 35 | display: inline-block; 36 | 37 | cursor: pointer; 38 | user-select: none; 39 | text-align: center; 40 | vertical-align: middle; 41 | white-space: nowrap; 42 | 43 | border: 1px solid transparent; 44 | border-radius: @btn-border-radius; 45 | outline: none; 46 | background-image: none; 47 | 48 | touch-action: manipulation; 49 | .button-size(@btn-font-size, @btn-padding); 50 | } 51 | 52 | .btn-default { 53 | .button-style(@btn-default-bg, 54 | @btn-default-color, 55 | @btn-default-hover-bg, 56 | @btn-default-hover-color); 57 | } 58 | 59 | .btn-info { 60 | .button-style(@btn-info-bg, 61 | @btn-info-color, 62 | @btn-info-hover-bg, 63 | @btn-info-hover-color); 64 | } 65 | 66 | .btn-secondary { 67 | .button-style(@btn-secondary-bg, 68 | @btn-secondary-color, 69 | @btn-secondary-hover-bg, 70 | @btn-secondary-hover-color); 71 | } 72 | 73 | 74 | 75 | // Размеры кнопок 76 | .btn-xs { 77 | .button-size(@btn-size-xs-font-size, @btn-size-xs-padding); 78 | } 79 | 80 | .btn-xl { 81 | .button-size(@btn-size-xl-font-size, @btn-size-xl-padding); 82 | } -------------------------------------------------------------------------------- /chapter_3/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание 2 | 3 | В этой главе вы узнали о том, что такое переменные, какие значения в них можно хранить и как их использовать на практике. Кроме того, вы познакомились с примесями, позволяющими повторно использовать блоки кода. Самое время выполнить домашнее задание на эту тему. 4 | 5 | 6 | 7 | 8 | ## Постановка задачи 9 | 10 | Необходимо разработать набор кнопок для сайта, используя все 11 | полученные знания из этой главы. 12 | 13 | 14 | 15 | ### Техническое задание 16 | 17 | Каждая кнопка имеет общий стиль, но при этом различается размерами и цветами. 18 | 19 | Обязательным условием выполнения будет использование переменных для хранения цветов, размеров и прочих величин, которые могут поменяться на любой стадии развития проекта. А также примесей, которые будут менять размер и цвет кнопки в зависимости от передаваемых параметров. 20 | 21 | Ниже приведены изображения кнопок, которые необходимо разработать. 22 | 23 | **Состояние до нажатия и после** 24 | 25 | ![](../images/chapter_3_homework_1.png) 26 | 27 | **Размеры кнопок** 28 | 29 | ![](../images/chapter_3_homework_2.png) 30 | 31 | Для домашнего задания я заранее подготовил таблицу со всеми значениями переменных, которые могут понадобиться вам в работе. 32 | 33 | **Цвет фона и шрифта** 34 | 35 | | Свойство | По умолчанию | Второй тип | Третий тип | 36 | |------------------|--------------|------------|------------| 37 | | background | #e0e0e0 | #3b83c0 | #404245 | 38 | | color | #333 | #fff | #fff | 39 | | hover background | #e8e8e8 | #458ac6 | #1b1c1d | 40 | | hover color | #333 | #fff | #fff | 41 | 42 | **Размеры** 43 | 44 | | Свойство | Маленький | Стандартный | Большой | 45 | |-------------|-----------|-------------|-----------| 46 | | font-size | 10px | 14px | 18px | 47 | | line-height | 20px | 20px | 20px | 48 | | padding | 2px 4px | 6px 12px | 10px 16px | 49 | 50 | Не волнуйтесь, у вас все получится! Если у вас возникают какие-либо сложности, то посмотрите решение этого задания в архиве, который прилагается к этой книге. 51 | 52 | > **Внимание** 53 | > 54 | > Решение этого домашнего задания будет предоставлено вместе с архивом 55 | примеров после завершения написания книги. 56 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Введение](README.md) 4 | * [Предисловие](chapter_0/introduction.md) 5 | * [Благодарности](chapter_0/thanks.md) 6 | * [Целевая аудитория](chapter_0/audience.md) 7 | * [Глава 1. Основы](chapter_1/intro.md) 8 | * [Препроцессоры](chapter_1/preprocessors.md) 9 | * [CSS-препроцессоры](chapter_1/css-reprocessors.md) 10 | * [Грань между Less и CSS](chapter_1/verge-less-css.md) 11 | * [Компиляция и отладка](chapter_1/compiling-and-debugging.md) 12 | * [Использование плагинов](chapter_1/usage-plugins.md) 13 | * [Глава 2. Работа с селекторами, медиа-запросами и файлами](chapter_2/intro.md) 14 | * [Комментарии](chapter_2/comments.md) 15 | * [Вложенные правила](chapter_2/nested-rules.md) 16 | * [Ссылка на родителя селектора](chapter_2/parent-selectors.md) 17 | * [Группировка селекторов](chapter_2/grouping-selectors.md) 18 | * [Использование медиавыражений](chapter_2/media-queries.md) 19 | * [Импорт стилей](chapter_2/import_styles.md) 20 | * [Домашнее задание](chapter_2/homework.md) 21 | * [Глава 3. Переменные и примеси](chapter_3/intro.md) 22 | * [Использование переменных](chapter_3/using-variables.md) 23 | * [Интерполяция переменных](chapter_3/variable-interpolation.md) 24 | * [Наименование переменных](chapter_3/variable-names.md) 25 | * [Использование примесей](chapter_3/using-mixins.md) 26 | * [Специальные параметры и сопоставление шаблонов](chapter_3/special-parameters-and-pattern-matching.md) 27 | * [Дополнительные возможности примесей](chapter_3/additional-features-of-mixins.md) 28 | * [Работа с набором правил](chapter_3/working-with-rulesets.md) 29 | * [Домашнее задание](chapter_3/homework.md) 30 | * [Глава 4. Операции со свойствами и встроенные функции](chapter_4/intro.md) 31 | * [Слияние свойств](chapter_4/merge-properties.md) 32 | * [Строки и списки](chapter_4/strings-and-lists.md) 33 | * [Работа с изображениями](chapter_4/working-with-images.md) 34 | * [Работа с типами данных и единицами измерения](chapter_4/working-with-data-types-and-units.md) 35 | * [Математические функции](chapter_4/math-functions.md) 36 | * [Манипуляции с цветами](chapter_4/manipulation-with-colors.md) 37 | * [Домашнее задание](chapter_4/homework.md) 38 | * [Глава 5. Инструкции (операторы)](chapter_5/intro.md) 39 | * [Условные конструкции (защита примесей)](chapter_5/if.md) 40 | * [Циклические конструкции](chapter_5/loops.md) 41 | * [Домашнее задание](chapter_5/homework.md) 42 | * [Глава 6. JavaScript в Less](chapter_6/intro.md) 43 | * [Обзор возможностей](chapter_6/features-overview.md) 44 | * [Работа с переменными и примесями](chapter_6/working-with-variables-and-mixins.md) 45 | -------------------------------------------------------------------------------- /chapter_1/preprocessors.md: -------------------------------------------------------------------------------- 1 | # Препроцессоры 2 | 3 | Пожалуй, начнём с определения: 4 | 5 | **Препроцессор** (от англ. Preprocessor) — это инструмент, преобразующий код из одного синтаксиса в другой. Обычно, на вход препроцессора поступает код, написанный с использованием синтаксических конструкций, понятных этому препроцессору. 6 | 7 | Стоит сказать, что препроцессор может полностью замещать синтаксические конструкции языка или частично расширять их, то есть добавлять новые конструкции. Так как препроцессор преобразует код, то помимо входа у него должен быть и выход. Иначе какой смысл в его работе, ведь другие программы не смогут воспользоваться его трудами. 8 | 9 | Как правило, на выходе ожидается код с более низким уровнем. То есть код, лишённый синтаксических конструкций, вносимых препроцессором. Сейчас нам не важно, что происходит с такими конструкциями, допустим, что препроцессор их раскрывает или удаляет в соответствии с заложенными в него правилами. Иначе говоря, на выходе мы получаем код, понятный программе, которая будет использовать его после препроцессора. 10 | 11 | 12 | 13 | ### Пример 14 | 15 | Рассмотрим работу препроцессора на простейшем примере. Условия задачи у нас будут такими: 16 | 17 | > Пусть на вход препроцессора поступает строка, включающая в себя последовательность слов, разделённых пробелами, запятыми и точками. Основная функция препроцессора — замена ключевого слова «.CSS.» на его полную форму записи «Cascading Style Sheets». На выходе препроцессора имеем преобразованную строку. 18 | 19 | Итак, исходя из условий мы понимаем, что «.CSS.» — это синтаксическая конструкция, которую должен обработать препроцессор. 20 | 21 | Допустим, что на вход была подана следующая строка: 22 | 23 | ``` 24 | Developers use CSS preprocessors to build .CSS. faster. 25 | ``` 26 | 27 | Как мы видим, в этой строке два раза встречается слово «CSS». В первом случае это будет обычным словом как, например, «use» или «build», а во втором — синтаксической конструкцией препроцессора. 28 | 29 | Далее препроцессор преобразует строку в соответствии с заложенным в него функционалом, и, в зависимости от настроек, на выходе имеется преобразованная строка. 30 | 31 | 32 | ``` 33 | Developers use CSS preprocessors to build Cascading Style Sheets faster. 34 | ``` 35 | 36 | Так работают препроцессоры в самом примитивном случае. В больших проектах все куда сложнее. 37 | 38 | 39 | 40 | ### Некоторые понятия 41 | 42 | Кстати, для того, чтобы понимать некоторые статьи и книги, нужно запомнить, что вместо слова «преобразует», могут использоваться слова «компилирует» и «транслирует». 43 | 44 | Если вы ничего не поняли из этой части главы, не расстраивайтесь — это нормально. Понимание придёт к вам на следующей странице. Конечно, при желании. 45 | -------------------------------------------------------------------------------- /chapter_1/verge-less-css.md: -------------------------------------------------------------------------------- 1 | # Грань между Less и CSS 2 | 3 | Если попытаться напрячь своё воображение и не вдаваться в подробности, то окажется, что вы уже используете препроцессор Less, хотя и косвенно. Да, это не шутка. Любой CSS-файл считается валидным Less-файлом. Для этого даже не нужно менять расширение файла. Однако, такое положение дел возможно, если вы подключаете этот файл к другому файлу, который уже имеет расширение `.less` или работаете с консолью. О том, как работать с файлами в Less я буду говорить позднее, а вот пример валидного Less-файла я обязательно приведу для большего понимания темы. 4 | 5 | Ниже приведён фрагмент самого обычного CSS-кода, который я использую у себя в проектах. Весь этот код хранится в файле `styles.css` вместе с сотнями других строчек, но нас интересует именно синтаксис, а не файл и его содержимое. 6 | 7 | ```css 8 | .area { 9 | margin-right: auto; 10 | margin-left: auto; 11 | } 12 | 13 | .area:before, 14 | .area:after { 15 | display: table; 16 | content: " "; 17 | } 18 | 19 | .area:after { 20 | clear: both; 21 | } 22 | 23 | @media (min-width: 768px) { 24 | .area { 25 | width: 750px; 26 | padding-right: 15px; 27 | padding-left: 15px; 28 | } 29 | } 30 | ``` 31 | 32 | Я думаю объяснять не стоит, что здесь мы имеем дело с обычным CSS. На этом этапе нам не важно, что и как делают эти строчки, главное, что они реальны и могут использоваться в любом CSS-файле уже сейчас. 33 | 34 | А теперь возьмём эти стили и, ничего не меняя, поместим их в файл с таким же именем, но имеющим расширение `.less`. Я понимаю, что до сих пор мы не рассматривали возможность компиляции less-файлов, но поверьте мне на слово — файл скомпилируется без ошибок и будет точно таким же по содержанию. 35 | 36 | ![](../images/chapter_1_less_to_css.png) 37 | 38 | На изображении выше представлено состояние less-файла до компиляции и после. Сразу видно, что они идентичны и различаются лишь наличием пустых строк после селекторов в Less-файле, а также расширением. 39 | 40 | Из всего этого напрашивается вывод, что даже если вы не будете использовать возможности Less полностью или будете пользоваться лишь некоторыми из них, то ничего страшного не случится. Вас никто не обязывает менять свой любимый синтаксис на какой-либо другой. Наоборот, препроцессор Less будет только рад этому, ведь в таком случае на компиляцию уйдёт меньше времени. Если говорить ещё проще, то препроцессор можно применять лишь для конкретных целей, например, для построения удобной и хорошо поддерживаемой структуры, которую можно организовать и на чистом CSS, но с меньшим удобством. 41 | 42 | О структуре проекта я подробнее расскажу ближе к концу этой удивительной истории, когда к вам, по идее, придёт понимание того, чем вы занимались на протяжении всего времени, проведённого с этой книгой. Поэтому не волнуйтесь — всему своё время. 43 | -------------------------------------------------------------------------------- /chapter_4/math-functions.md: -------------------------------------------------------------------------------- 1 | # Математические функции 2 | 3 | Для удобства работы с числами доступны математические функции, которые представляют собой прослойку между Less-функциями и встроенным объектом Math в JavaScript. 4 | 5 | Кратко рассмотрим основные функции, которые могут пригодиться при работе с препроцессором при построении фреймворков и максимально унифицированных less-файлов. 6 | 7 | 8 | 9 | 10 | ## Округление значений 11 | 12 | При необходимости значения, получаемые после проведения математических операций, можно округлять, используя стандартные методы `ceil()`, `floor()` и `round()`, представленные в Less в виде функций. Кроме того, Less предоставляет новую функцию `percentage()`. 13 | 14 | **Функция `ceil()`** всегда округляет значения в большую сторону до целой части: 15 | 16 | ```less 17 | ceil(14.3) // 15 18 | ceil(13.9) // 14 19 | ceil(14.5) // 15 20 | ``` 21 | 22 | **Функция `floor()`** всегда округляет значения в меньшую сторону до целой части (отбрасывает дробную часть): 23 | 24 | ```less 25 | floor(14.3) // 14 26 | floor(13.9) // 13 27 | floor(14.5) // 14 28 | ``` 29 | 30 | **Функция `round()`** округляет значения в соответствии с правилами математики и заданным количеством знаков после запятой: 31 | 32 | ```less 33 | round(14.3) // 14 34 | round(13.9) // 14 35 | round(14.5) // 15 36 | 37 | // Знаки после запятой 38 | round(14.0714) // 14 39 | round(14.0714, 1) // 14.1 40 | round(14.0714, 2) // 14.07 41 | round(14.0714, 3) // 14.071 42 | round(14.0714, 4) // 14.074 43 | round(14.0714, 7) // 14.074 44 | ``` 45 | 46 | **Функция `percentage()`** преобразует дробное значение в процентное: 47 | 48 | ```less 49 | percentage(0.25) // 25% 50 | percentage(1 / 25) // 4% 51 | ``` 52 | 53 | Важно заметить, что дробная запись `1 / 25` сначала вычисляется как математическая операция, а уже потом передаётся в функцию. То есть, по сути своей, работает с числами с плавающей запятой. 54 | 55 | 56 | 57 | 58 | ## Прочие функции 59 | 60 | Математические функции, представленные ниже, являются вторичными и применяются крайне редко. Дело в том, что возможность применять Less для сложных вычислений предоставляется очень редко, ведь это всего-лишь надстройка над CSS. 61 | 62 | Тригонометрические функции: 63 | 64 | * `sin(value)` 65 | * `cosvalue)` 66 | * `tan(value)` 67 | 68 | Обратные тригонометрические функции: 69 | 70 | * `asin(value)` 71 | * `acos(value)` 72 | * `atan(value)` 73 | 74 | Модуль числа, модуль между числами: 75 | 76 | * `abs(value)` 77 | * `mod(valueOne, valueTwo)` 78 | 79 | Поиск минимального и максимального значения: 80 | 81 | * `min(list)` // min(1, 14, 19, 0.3) 82 | * `max(list)` // max(1%, 10%, 4%, 8%) 83 | 84 | Работа со степенями (квадратный корень и степень): 85 | 86 | * `sqrt(value)` 87 | * `pow(value, power)` // value в power степени 88 | 89 | Математические константы: 90 | 91 | * `pi()` 92 | -------------------------------------------------------------------------------- /chapter_2/comments.md: -------------------------------------------------------------------------------- 1 | # Комментарии 2 | 3 | Хороший код должен сопровождаться комментариями, хотя и бытует мнение, что прекрасный код вовсе не нуждается в них. Конечно, повсеместно писать комментарии не нужно, а вот ключевые моменты лучше всего сопровождать короткими записками. 4 | 5 | Комментарии делают ваш код чище, а также помогают достичь понимания с другими разработчиками, работающими с вашим кодом. Самое главное, чтобы вы сами понимали то, что написали и старались излагать свои мысли максимально кратко, ясно и однозначно. 6 | 7 | Если проект, над которым вы работаете используется не только вашим отделом, компанией или внутренним сообществом, то целесообразнее писать комментарии на английском языке. Иначе, если ваш проект применяется только внутри одной компании, в которой официальным языком принят, например, русский язык, то логичнее всего будет использовать именно его. 8 | 9 | 10 | 11 | 12 | ## Базовый синтаксис 13 | 14 | Препроцессор Less поддерживает несколько синтаксисов написания комментариев. Самый очевидный — это стандартный для CSS синтаксис. Если отключена минификация (компрессия, сжатие) кода, то такие комментарии, содержащиеся между `/* */`, будут сохраняться в CSS-файле после компиляции. Поэтому используйте такой вид комментариев с умом. 15 | 16 | ```less 17 | /* Это стандартный однострочный комментарий для CSS */ 18 | 19 | /* 20 | А это стандартный блочный комментарий для CSS. 21 | При необходимости можно использовать и его. 22 | */ 23 | ``` 24 | 25 | Помимо стандартного синтаксиса предлагается и препроцессорный, но только лишь однострочный вариант записи. Комментарии начинающиеся с `//` не будут сохраняться в CSS-файл после компиляции. 26 | 27 | ```less 28 | // Это препроцессорный однострочный комментарий 29 | ``` 30 | 31 | 32 | 33 | 34 | ## Особые комментарии 35 | 36 | Иногда требуется сохранить какие-то комментарии после компиляции и даже минификации кода. Такой подход чаще всего используется для включения в файл информации о лицензии, авторских правах, версии библиотеки и прочих важных сообщений. Как и в CSS для этого используются комментарии, заключённые в `/*! */`. 37 | 38 | ```less 39 | /*! Комментарий, который будет всегда сохраняться */ 40 | ``` 41 | 42 | Также допустима запись `/*! !*/`, но она считается избыточной и применяется крайне редко, если вообще применяется. 43 | 44 | ```less 45 | /*! Комментарий, который будет всегда сохраняться !*/ 46 | ``` 47 | 48 | 49 | 50 | 51 | ## Вложенные комментарии 52 | 53 | К сожалению, вкладывать комментарии в комментарии, как и CSS, Less не умеет. Однако, допустимо смешивать комментарии, заключённые в `/* */` и однострочные комментарии, начинающиеся с `//`. 54 | 55 | ```less 56 | /* 57 | // Смешивание комментариев 58 | */ 59 | ``` 60 | 61 | Можно попытаться вложить комментарии и наоборот: 62 | 63 | ```less 64 | // /* Этот комментарий вложен в другой комментарий */ 65 | ``` 66 | 67 | После компиляции less-файлов, в первом случае комментарий будет отображаться в скомпилированном CSS-файле, а вот втором случае — нет. 68 | -------------------------------------------------------------------------------- /chapter_2/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание 2 | 3 | В этой главе вы узнали, как можно работать с селекторами в Less, использовать медиавыражения и импортировать файлы друг в друга. Для закрепления полученных знаний я советую выполнить несложное домашнее задание. 4 | 5 | 6 | 7 | 8 | ## Постановка задачи 9 | 10 | Необходимо разработать главную страницу простейшей галереи, используя все полученные знания из этой главы. 11 | 12 | 13 | 14 | ### Техническое задание 15 | 16 | Главная страница галереи адаптируется под необходимые устройства и имеет четыре основных состояния отображения, каждое из которых подробно рассматривается ниже. 17 | 18 | Так как это домашнее задание, а не реальный проект, то для упрощения его выполнения, я предоставлю всю необходимую информацию заранее: 19 | 20 | **Стилевое оформление:** 21 | 22 | * Фон области с заголовком: `#ecf0f1`; 23 | * Фон области с картинками: `#bdc3c7`; 24 | * Расстояние между картинками: `20px`; 25 | * При фокусе и наведении мышки на картинки их прозрачность должна быть `0.5`; 26 | 27 | **Размеры контейнеров и точки для медиавыражений:** 28 | 29 | * Настольные компьютеры и ноутбуки: `992px и больше` (контейнер: `970px`); 30 | * Планшеты: `от 768px до 992px` (контейнер: `750px`); 31 | * Смартфоны: `от 540px до 768px`; 32 | * Мобильные телефоны: `от 0px до 540px`; 33 | 34 | Размер шрифта заголовка, сам шрифт, его цвет и отступы не имеют значения в рамках этой задачи. Кроме того, картинки представленные ниже на скриншотах предлагается заменить на свои. Лучше всего, если это будут картинки котиков. 35 | 36 | 37 | #### Настольные компьютеры и ноутбуки 38 | 39 | При разрешении окна браузера больше `992px` требуется, чтобы контент располагался посередине страницы и занимал `970px` ширины. При этом картинки располагались в ряд по **пять** штук и занимали всю предоставленную им площадь. 40 | 41 | ![](../images/chapter_2_homework_1.png) 42 | 43 | 44 | #### Планшеты 45 | 46 | На планшетных компьютерах требуется, чтобы все условия, описанные ранее, соблюдались в полной мере, с той лишь разницей, что ширина области контента равнялась `750px`, а картинки располагались по **три** в ряд. 47 | 48 | ![](../images/chapter_2_homework_2.png) 49 | 50 | 51 | #### Смартфоны 52 | 53 | Необходимо, чтобы на смартфонах картинки располагались по **две** в ряд, а область контента занимала всю доступную ширину окна браузера. 54 | 55 | ![](../images/chapter_2_homework_3.png) 56 | 57 | 58 | #### Мобильные телефоны 59 | 60 | Мобильные телефоны должны отображать картинки по **одной** в строке, то есть друг за другом в столбце. Область контента должна занимать всю доступную ширину окна браузера. 61 | 62 | ![](../images/chapter_2_homework_4.png) 63 | 64 | 65 | 66 | ### Советы 67 | 68 | При желании используйте все доступные вам технологии и приёмы. Желательно, чтобы в решении использовались (но не обязательно): 69 | 70 | * Блочная модель `border-box`; 71 | * [normalize.css](http://necolas.github.io/normalize.css/); 72 | 73 | Не волнуйтесь, у вас все получится! Если у вас возникают какие-либо сложности, то посмотрите решение этого задания в архиве, который прилагается к этой книге. 74 | -------------------------------------------------------------------------------- /chapter_0/introduction.md: -------------------------------------------------------------------------------- 1 | # Предисловие 2 | 3 | По моему мнению, революция, которую совершили CSS-препроцессоры полностью перевернула представление о написании стилей. Многие люди уже тогда рассматривали возможность перехода с «чистого» CSS на препроцессорный. Такие миграции продолжаются до сих пор, но с умеренным темпом, так как основная масса разработчиков уже стала использовать этот удобный инструмент. Даже самые упёртые и недоверчивые сторонники «чистого» CSS начали бросать свои взгляды на препроцессоры. 4 | 5 | Сейчас рынок препроцессоров делится на три основных лагеря. Для того, чтобы люди могли сделать правильный выбор, многие разработчики пишут статьи, в которых рассказывают о преимуществах одного CSS-препроцессора перед другими. Такие статьи будут интересны всем без исключения, хотя бы ради холивара и вечных споров. Однако, этот интерес утихнет тогда, когда вы выберете себе инструмент по душе. Таким инструментом для меня стал Less, которому и будет посвящена эта книга. 6 | 7 | В этой книге речь пойдёт об одном из самых популярных CSS-препроцессоров — Less. Во многом, Less получил свою популярность благодаря практически родному для CSS синтаксису, лёгкому в освоении функционалу, фреймворку Bootstrap, отличной и доступной документации, а также тому, что он написан на JavaScript. А, как известно, нет ничего роднее, ближе и удобнее для веб-разработчика, чем JavaScript. Возможно, для многих Ruby (на нём были написаны первые версии Less) ближе, но не для меня. 8 | 9 | Эта книга — не энциклопедия и не справочник по Less. Здесь вы не найдёте сухого описания всех возможностей этого препроцессора, дословного перевода или пересказа документации, а также скучных примеров, которые никому не нужны, кроме автора. Моя задача — познакомить вас с этим препроцессором, дать базовое представление о нём и помочь организовать работу с ним. Проще говоря, моя цель — это направить вас на путь истинный. 10 | 11 | Повторюсь, что в рамках этой книги я постараюсь максимально простым языком, понятным даже новичкам, рассказать о возможностях Less. И для того, чтобы это сделать максимально понятно, я буду использовать большое количество примеров, заданий и разговоров о том, почему лучше делать так, а не иначе. 12 | 13 | Все примеры в этой книге будут составляться таким образом, чтобы охватывать реальные ситуации. Однако, в некоторых частях книги возможно появление так называемых примеров из сферического вакуума, которые полностью отображают суть проблемы и её решения, но в повседневной разработке встречаются крайне редко или не встречаются вовсе. 14 | 15 | Под заданиями я понимаю тематические упражнения, нацеленные на закрепление пройденного материала. Без попыток применения полученных знаний на практике — ваши знания равны нулю. Нет ничего лучше, чем бросаться с некоторым количеством знаний в голове на реальную задачу. 16 | 17 | 18 | 19 | 20 | # Возможные опечатки и неточности 21 | 22 | Я могу допускать ошибки, ошибаться и говорить всякий бред. Поэтому не стоит читать эту книгу с надеждой на то, что это единственное лекарство от всех ваших бед. Прочитав эту книгу, вы не станете успешным веб-разработчиком, а всего лишь познакомитесь с такой технологией, вернее даже сказать, инструментом, как CSS-препроцессор Less. 23 | -------------------------------------------------------------------------------- /chapter_1/usage-plugins.md: -------------------------------------------------------------------------------- 1 | # Использование плагинов 2 | 3 | Как я уже отмечал ранее, CSS-препроцессор Less имеет возможность подключения плагинов, расширяющих основной функционал препроцессора. Все доступные на сегодняшний момент плагины можно найти в пакетном менеджере npm, используя для поиска ключевое слово — `"less-plugin"`. Среди них довольно большое количество интересных и даже необходимых плагинов. Однако, давайте сначала посмотрим на то, как подключать плагины при компиляции less-файлов из консоли. 4 | 5 | Дальнейшие манипуляции будут производиться с плагином `less-plugin-functions`, добавляющим возможность создания пользовательских функций. 6 | 7 | Первым делом установим этот плагин локально или глобально. Я буду устанавливать глобально, поэтому у себя в консоли выполняю следующую команду: 8 | 9 | ``` 10 | $ npm i -g less-plugin-functions 11 | ``` 12 | 13 | Теперь обратимся к документации плагина и напишем небольшой пример, демонстрирующий работу функций: 14 | 15 | ```less 16 | // Исходя из документации, функции всегда должны начинаться со слова `function` 17 | .function-hello() { 18 | return: "Hello!"; 19 | } 20 | 21 | // Вызов функции производится без ключевого слова `function` 22 | .test { 23 | content: hello(); 24 | } 25 | 26 | ``` 27 | 28 | Когда компилятор встретит на своём пути какую-нибудь функцию, он подставит вместо её вызова значение, возвращаемое этой функцией. Всё как в JavaScript. Для того, чтобы скомпилировать этот файл, необходимо выполнить команду: 29 | 30 | ``` 31 | $ lessc --functions styles.less 32 | .test { 33 | content: "Hello!"; 34 | } 35 | ``` 36 | 37 | Заметьте, так как я не указал имя файла, в который компилятору необходимо сохранить результат компиляции — полученный результат был выведен в консоль. 38 | 39 | Разумеется, простым возвращением результата функционал этого плагина не заканчивается: вы можете производить вычисления, конкатенировать значения свойств, вызывать другие функции и примеси... 40 | 41 | Чтобы применить к файлу несколько плагинов, необходимо просто добавить их в команду, выполняемую в консоли: 42 | 43 | ``` 44 | $ lessc --functions --inline-urls styles.less 45 | ``` 46 | 47 | 48 | 49 | 50 | ## Использование плагинов в браузере 51 | 52 | В документации сказано, что любой плагин может работать с компилятором, подключаемым как внешний скрипт к странице с одним лишь условием: подключение плагина и его описание должно быть произведено раньше, чем будет подключён сам файл библиотеки `less.js`: 53 | 54 | ```html 55 | 56 | 61 | 62 | ``` 63 | 64 | Здесь кроется одна большая проблема — чтобы начать использовать плагины в браузере, необходимо найти хотя бы один плагин, который способен это делать без предварительной сборки. Дело в том, что браузер не умеет работать с `require()`, используемым для подключения файлов скриптов в мире Node.js. Почти все плагины используют `require()`, так как разбиты на несколько логических файлов. Поэтому, перед тем, как приступить к подключению заветного плагина к странице — его нужно собрать, используя для этого, например, Browserify. К счастью, это не входит в план книги. 65 | -------------------------------------------------------------------------------- /chapter_4/merge-properties.md: -------------------------------------------------------------------------------- 1 | # Слияние свойств 2 | 3 | При создании набора примесей может понадобиться манипулировать значениями свойств, то есть адаптировать их в зависимости от контекста использования, используя условные конструкции (подробнее смотрите в главе 5). 4 | 5 | Для начала рассмотрим пример, отображающий проблему при вызове двух примесей, имеющих одинаковые свойства. 6 | 7 | ```less 8 | .depth-top() { 9 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16); 10 | } 11 | 12 | .depth-bottom() { 13 | box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.12); 14 | } 15 | ``` 16 | 17 | Допустим, что имеется код, который генерирует одно и тоже свойство, но с разными значениями. В первом случае это будет тень сверху блока, а во-втором — снизу. С таким подходом можно встретиться в модном сейчас направлении — материальный дизайн. Вызовем эти примеси для какого-нибудь произвольного блока: 18 | 19 | ```less 20 | .block { 21 | .depth-top(); 22 | .depth-bottom(); 23 | } 24 | ``` 25 | 26 | Как не сложно было догадаться, мы получили два одинаковых свойства, но значения у них разные. В таком подходе кроется одна большая проблема. 27 | 28 | ```css 29 | .block { 30 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16); 31 | box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.12); 32 | } 33 | ``` 34 | 35 | И проблема эта в том, что второе свойство переопределит первое. Это приведёт к тому, что тень не будет состоять из верхней и нижней частей — браузер покажет лишь нижнюю, так как она стоит ниже в селекторе и заменяет собой верхнюю. 36 | 37 | Благодаря Less значения свойств можно конкатенировать, и делается это двумя способами: 38 | 39 | * Через запятую (свойства `box-shadow`, `font-family` и т.д.) 40 | * Через пробел (свойства `transform`, `text-overflow` и т.д.) 41 | 42 | 43 | 44 | 45 | ## Слияние свойств через запятую 46 | 47 | Для того, чтобы решить проблему, просто добавим плюс (+) перед двоеточием свойства. Это скажет компилятору, что при встречи двух одинаковых свойств в одном селекторе — его целью будет их объединение. 48 | 49 | ```less 50 | .depth-top() { 51 | box-shadow+: 0 2px 5px 0 rgba(0, 0, 0, 0.16); 52 | } 53 | 54 | .depth-bottom() { 55 | box-shadow+: 0 2px 10px 0 rgba(0, 0, 0, 0.12); 56 | } 57 | ``` 58 | 59 | После компиляции результат оправдает ожидание. Свойство одно и оно включает в себя конкатенированное значение двух примесей, записанных через запятую, что и соответствует синтаксису этого свойства. 60 | 61 | ```css 62 | .block { 63 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); 64 | } 65 | ``` 66 | 67 | Важно заметить, что такой подход будет работать только со свойствами, у которых указан плюс перед двоеточием. То есть, если у селектора уже есть свойство `box-shadow` без явного указания на необходимость слияния значений, то конкатенация значений проводиться не будет. 68 | 69 | 70 | 71 | 72 | ## Слияние свойств через пробел 73 | 74 | По сути своей, никакого отличия от слияния свойств через запятую здесь нет — добавляется лишь нижнее подчёркивание после плюса перед двоеточием. 75 | 76 | ```less 77 | .scale(@scale) { 78 | transform+_: scale(@scale); 79 | } 80 | 81 | .rotate(@angle) { 82 | transform+_: rotate(@angle); 83 | } 84 | 85 | .translate(@px) { 86 | transform+_: translateX(@px); 87 | } 88 | 89 | .block { 90 | .scale(1.75); 91 | .rotate(45deg); 92 | .translate(10px); 93 | } 94 | ``` 95 | 96 | В результате, после компиляции получим следующее валидное для этого свойства значение: 97 | 98 | ```css 99 | .block { 100 | transform: scale(1.75) rotate(45deg) translateX(10px); 101 | } 102 | ``` 103 | -------------------------------------------------------------------------------- /chapter_4/working-with-data-types-and-units.md: -------------------------------------------------------------------------------- 1 | # Работа с типами данных и единицами измерения 2 | 3 | ## Функции для работы с единицами измерений 4 | 5 | При написании примесей может понадобиться проверять переданные параметры при вызове, используя условные конструкции. Для этого Less имеет следующие функции: 6 | 7 | * `convert()` 8 | * `unit()` 9 | * `get-unit()` 10 | 11 | Давайте поговорим немного подробнее о каждой из них. 12 | 13 | 14 | 15 | ### Функция `convert()` 16 | 17 | Как несложно догадаться, эта функция преобразует одну единицу измерения в другую. Принцип её работы очень прост: 18 | 19 | * Если единицы измерения совместимы, то происходит преобразование и возвращается преобразованное число. 20 | * Если единицы измерения не совместимы, то возвращается число без преобразований. 21 | 22 | Список поддерживаемых единиц измерения: 23 | 24 | * Длина: `m`, `cm`, `mm`, `in`, `pt` и `pc`. 25 | * Время: `s` и `ms`. 26 | * Углы: `rad`, `deg`, `grad` и `turn`. 27 | 28 | Например, если нужно конвертировать метры в миллиметры, то функцию следует записать так: 29 | 30 | ```less 31 | .selector { 32 | content: convert(10m, "mm"); 33 | // В результате 34 | // 10000mm 35 | } 36 | ``` 37 | 38 | 39 | 40 | ### Функция `unit()` и `get-unit()` 41 | 42 | Обе функции предназначены для получения информации о переданном числе. Первая функция отбрасывает единицы и возвращает число, а вторая наоборот — отбрасывает число и возвращает единицы измерения. 43 | 44 | Посмотрим на результат работы функций, если на вход подать различные данные. Для простоты и наглядности селектор и свойство убраны. 45 | 46 | ```less 47 | unit(10px) // 10 48 | unit(10rem) // 10 49 | unit(10cm) // 10 50 | 51 | // Такой единицы нет в CSS 52 | unit(10apple) // 10 53 | ``` 54 | 55 | Обратите внимание, что функция `unit()` не анализирует передаваемые ей данные, а просто возвращает число. Однако, если передать строку, то компилятор заподозрит что-то неладное и породит ошибку. 56 | 57 | В случае с функцией `get-unit()` ситуация идентичная, исключая то, что при передаче строки ошибки не будет: 58 | 59 | ```less 60 | get-unit(10px) // px 61 | get-unit(10rem) // rem 62 | get-unit(10cm) // cm 63 | 64 | // Такой единицы нет в CSS 65 | get-unit(10apple) // apple 66 | 67 | // Строка 68 | get-unit("10string") // "" 69 | ``` 70 | 71 | 72 | 73 | 74 | ## Работа с типами данных 75 | 76 | Для определения типа данных в Less можно прибегнуть к помощи встроенных функций, которые возвращают логическое значение `true` или `false`. 77 | 78 | Набор таких функций покрывает все типы, используемые в препроцессоре. 79 | 80 | * `isnumber(value)` 81 | * `isstring(value)` 82 | * `iscolor(value)` 83 | * `iskeyword(value)` 84 | * `isurl(value)` 85 | * `ispixel(value)` 86 | * `isem(value)` 87 | * `ispercentage(value)` 88 | * `isruleset(value)` 89 | 90 | Как следует из названия функций, каждая из них проверяет является ли переданное в неё значение валидным. Однако, существует несколько особенностей, которые стоит запомнить: 91 | 92 | * Функция `isnumber(value)` не анализирует единицы измерения. 93 | * Функция `iscolor(value)` поддерживает все принятые в CSS варианты записи цвета. 94 | 95 | Отдельного внимания заслуживает функция `isunit()`, которая в отличие от других функций принимает на вход два параметра. Первый параметр — это значение, а второй — единицы измерения. 96 | 97 | Синтаксис функции имеет следующий вид: 98 | 99 | ```less 100 | isunit(value, unit) 101 | ``` 102 | 103 | Эта функция работает следующим образом: 104 | 105 | * Получаем единицы измерения параметра `value`. 106 | * Сравниваем единицы измерения параметра `value` со значением параметра `unit`. 107 | * Если значения равны, то возвращается `true`, иначе `false`. 108 | -------------------------------------------------------------------------------- /chapter_3/variable-names.md: -------------------------------------------------------------------------------- 1 | # Наименование переменных 2 | 3 | > В этой части главы я поделюсь с вами тактикой наименования и использования переменных. Вся информация, представленная здесь, основывается на многолетнем опыте работы с Less и большом количестве руководств по написанию таблиц стилей. У вас есть основания не доверять мне, но я бы советовал все же прочитать и обдумать описанные методики. 4 | 5 | Для того, чтобы погрузиться в «программирование» на Less, как и в любом другом языке, нужно правильно именовать переменные. Я не шучу, это очень важная и животрепещущая тема для всех новичков и даже тех, кто уже может себя по праву считать заслуженным программистом. 6 | 7 | 8 | 9 | 10 | ## Имя переменной 11 | 12 | Когда переменная имеет имя `a` или `razmer-wrifta`, а правила наименования меняются каждые десять строк, то уже сразу можно говорить о разработчике плохо. Просто примите как должное, что название переменной должно быть на английском языке, вне зависимости от того, на каком языке написаны комментарии к коду. Будь вы хоть трижды патриот своей страны или вы не знаете английский. 13 | 14 | **Хорошим примером могут послужить следующие переменные:** 15 | 16 | ```less 17 | @body-background: #f5f5f5; 18 | @body-font-size: 14px; 19 | @header-background: #fff; 20 | @btn-border-radius: 4px; 21 | @navbar-item-line-height: 20px; 22 | ``` 23 | 24 | 25 | 26 | 27 | ## Разделение слов в имени 28 | 29 | Используйте дефис, нижнее подчёркивание (under_score) или верблюжью нотацию (camelCase) для разделения слов в имени переменных. 30 | 31 | **Хорошим примером могут послужить следующие переменные:** 32 | 33 | ```less 34 | // Дефис 35 | @grid-breakpoint-xsmall: 540px; 36 | @navbar-item-color: #777; 37 | @pagination-border-color: #ddd; 38 | 39 | // Нижнее подчёркивание (under_score) 40 | @hamburger_border_radius: @border_radius; 41 | @line_height_computed: 24px; 42 | @font_awesome_path: "../vendor/font-awesome/font"; 43 | 44 | // Верблюжья нотация (camelCase) 45 | @labelFontSize: 0.8em; 46 | @commentBackground: #FFFFFF; 47 | @authorHoverColor: @primaryColorHover; 48 | ``` 49 | 50 | 51 | 52 | 53 | ## Содержательное имя 54 | 55 | Старайтесь давать переменным такие имена, которые сочетают в себе простоту, содержательность и логичность. 56 | 57 | **Хорошим примером могут послужить следующие переменные:** 58 | 59 | ```less 60 | @brand-color: #ffff66; 61 | @btn-default-background: #fcfcfc; 62 | @btn-default-hover-background: #ccc; 63 | @article-item-title-hover-color: @brand-color; 64 | ``` 65 | 66 | 67 | 68 | ## Последовательность имени 69 | 70 | Самым трудным по праву считается соблюдение баланса между простотой, содержательностью и логичностью имени переменной. В идеале нужно, чтобы имя было коротким и рассказывало все о переменной и контексте её применения. 71 | 72 | Рассмотрим последовательность имени переменных на основе разметки: 73 | 74 | ```html 75 |
76 |
77 |

78 | Заголовок 79 |

80 |
81 |
82 |

Текст карточки

83 |
84 | 90 |
91 | ``` 92 | 93 | **Хорошим примером могут послужить следующие переменные:** 94 | 95 | ```less 96 | @article-card-background: #fff; 97 | @article-card-border-radius: 4px; 98 | 99 | // Цвет и размер шрифта ссылки в заголовке 100 | @article-card-title-color: #777; 101 | @article-card-title-hover-color: #333; 102 | @article-card-title-font-size: 2.4rem; 103 | 104 | // Размер шрифта блока контента 105 | @article-card-content: 1.6rem; 106 | 107 | // Виджет тегов 108 | // Переиспользуемое представление тегов 109 | // В различных частях макета 110 | @tag-item-color: #777; 111 | @tag-item-hover-color: #333; 112 | ``` 113 | 114 | 115 | 116 | 117 | ## Единый стиль 118 | 119 | Используйте единый стиль наименования переменных. Например, если вы один раз использовали дефис для разделения слов в имени переменных, то используйте его во всём проекте. 120 | -------------------------------------------------------------------------------- /chapter_6/features-overview.md: -------------------------------------------------------------------------------- 1 | # Обзор возможностей 2 | 3 | Одной из самых интересных особенностей препроцессора Less является то, что его создатели предусмотрели возможность исполнения JavaScript-кода в less-файлах. Казалось бы, это весомое преимущество и полная свобода действий, но не всё так просто. 4 | 5 | Во-первых, JavaScript-код может быть лишь частью операции присвоения (переменные, свойства). Это означает, что введённая строка, содержащая JavaScript-код, будет интерпретироваться компилятором и обрабатываться. 6 | 7 | Во-вторых, компилятор накладывает сразу несколько ограничений: 8 | 9 | * Если возвращаемый результат число, то оно преобразуется к строке. 10 | * Если возвращаемый результат строка, то она заключается в кавычки. 11 | * Если возвращаемый результат массив, то все элементы массива конкатенируются и возвращаются как строка. 12 | * Если ни одно из выше перечисленных условий не работает, то результат просто приводится к строке. 13 | 14 | Отсюда следует самое главное ограничение — **результатом интерпретации выражения всегда будет строка**. 15 | 16 | Это очень сильно ограничивает возможность использования столь диковинной для CSS-препроцессора функции. 17 | 18 | Так как же намекнуть компилятору о том, что перед ним не просто строка, содержащая JavaScript-код, а строка, которую следует интерпретировать? — очень просто: 19 | 20 | ```less 21 | @js: `выражение`; 22 | ``` 23 | 24 | Иногда может понадобиться избавиться от обрамляющих кавычек. Для этого применяется ранее рассмотренная тильда (`~`), позволяющая экранировать содержимое строки: 25 | 26 | ```less 27 | @js: ~`выражение`; 28 | ``` 29 | 30 | Достаточно всего лишь обернуть строку, код которой необходимо интерпретировать в апострофы. 31 | 32 | > **Замечание** 33 | > 34 | > Не используйте точку с запятой перед закрывающим апострофом. В противном случае вы получите ошибку интерпретации. 35 | 36 | 37 | 38 | 39 | ## Простейшие выражения 40 | 41 | Простейшими, интерпретируемыми выражениями могут быть любые инструкции. Ниже я предлагаю рассмотреть некоторые из возможных JavaScript-инструкций, которые вы можете использовать в компиляторе Less. 42 | 43 | Для начала компилятор может просто вернуть число или, допустим, массив: 44 | 45 | ```less 46 | .test-js { 47 | content: `1`; 48 | content: `[1, 2, 3]`; 49 | } 50 | 51 | // После компиляции 52 | .test-js { 53 | content: 1; 54 | content: 1, 2, 3; 55 | } 56 | ``` 57 | 58 | Заметьте, что массив был возвращён как строка, о чём и говорилось в самом начале. 59 | 60 | Теперь посмотрим на то, что компилятор умеет складывать числа и даже считать математические функции: 61 | 62 | ```less 63 | .test-js { 64 | content: `1 + 6 + Math.cos(1)`; 65 | } 66 | 67 | // После компиляции 68 | .test-js { 69 | content: 7.54030231; 70 | } 71 | ``` 72 | 73 | Помимо каких-либо арифметических операций можно обращаться к методам Node.js, если вы компилируете код под этой платформой: 74 | 75 | ```less 76 | .test-js { 77 | content: `process.platform`; 78 | } 79 | ``` 80 | 81 | Так как моей основной платформой пока ещё является Windows, то результат можно легко предугадать: 82 | 83 | ```css 84 | .test-js { 85 | content: "win32"; 86 | } 87 | ``` 88 | 89 | Однако, никто не запрещает использовать JavaScript на полную в разумных пределах. В следующем примере выводится информация об используемой памяти процессом Node.js в байтах: 90 | 91 | ```less 92 | .test-js { 93 | content: `JSON.stringify(process.memoryUsage())`; 94 | } 95 | 96 | // Компилируется в 97 | .test-js { 98 | content: "{"rss":23982080,"heapTotal":15454976,"heapUsed":8824096}"; 99 | } 100 | ``` 101 | 102 | Для особых ценителей уточню, что использовать `require()` здесь нельзя, поэтому поднять веб-сервер в less-файле нельзя. Зато можно писать функции: 103 | 104 | ```less 105 | .test-js { 106 | content: `(function() { 107 | var a = 2; 108 | var b = Math.pow(a, 4); 109 | 110 | return a + b; 111 | })()`; 112 | } 113 | ``` 114 | 115 | Результатом работы этого выражения будет число 18 (`a = 2`, `b = 16`), как несложно догадаться, преобразованное к строке: 116 | 117 | ```css 118 | .test-js { 119 | content: 18; 120 | } 121 | ``` 122 | -------------------------------------------------------------------------------- /chapter_3/additional-features-of-mixins.md: -------------------------------------------------------------------------------- 1 | # Дополнительные возможности примесей 2 | 3 | Для наглядности я попытался разделить базовые возможности примесей от тех, что можно считать дополнительными. Конечно, все они нужны и важны, но дополнительные возможности все таки используются не часто. Можно даже сказать, что такие возможности практически не используются в виду их специфичности и области применения. 4 | 5 | 6 | 7 | 8 | ## Примеси как функции 9 | 10 | Идеология функции заключается в том, что она должна возвращать значение, а её вызов можно использовать как выражение. В Less организована работа лишь первой части этого утверждения. 11 | 12 | Для примера я приведу код, используемый для генерации иконки меню. Сейчас такую иконку называют «гамбургером» из-за своего внешнего вида. 13 | 14 | ```less 15 | .hamburger-settings(@width: 32px, @height: 3px, @gutter: 5px, @color: #000, 16 | @border-radius: 0, @duration: .3s, 17 | @timing-function: ease) { 18 | @hamburger-width: @width; 19 | @hamburger-height: @height; 20 | @hamburger-gutter: @gutter; 21 | @hamburger-color: @color; 22 | @hamburger-border-radius: @border-radius; 23 | @hamburger-duration: @duration; 24 | @hamburger-timing-function: @timing-function; 25 | } 26 | ``` 27 | 28 | В том месте, где необходимо получить эти настройки, нужно просто вызвать эту функцию. При этом изменив необходимые значения. 29 | 30 | ```less 31 | .hamburger-settings(24px, 3px, 5px, #777, @timing-function: linear); 32 | ``` 33 | 34 | Суть этого метода в том, чтобы дать пользователю в удобном для него виде изменять настройки библиотеки. 35 | 36 | С помощью этого свойства примесей можно организовать настоящие математические функции, разумеется, если это необходимо. 37 | 38 | Например, площадь треугольника, если известно основание и высота: 39 | 40 | ```less 41 | .areaTriangle(@a, @h) { 42 | @calcAreaTriangle: (0.5 * @a * @h); 43 | } 44 | 45 | .class { 46 | .areaTriangle(20, 50); 47 | content: @calcAreaTriangle; 48 | } 49 | ``` 50 | 51 | или переводить единицы измерения: 52 | 53 | ```less 54 | .pxToEm(@value, @base: 16px) { 55 | @calcEm: (@value / @base) + 0em; 56 | } 57 | 58 | .class { 59 | .pxToEm(20px); 60 | content: @calcEm; 61 | } 62 | ``` 63 | 64 | или найти среднее между двумя числами: 65 | 66 | ```less 67 | .average(@x, @y) { 68 | @calcAverage: ((@x + @y) / 2); 69 | } 70 | 71 | .class { 72 | .average(30px, 50px); 73 | padding: @calcAverage; 74 | } 75 | ``` 76 | 77 | 78 | 79 | 80 | ## Пространство имён 81 | 82 | Пространства имён представляют собой способ организации различных примесей. Их можно сравнить с директориями в файловой системе или с ящиками в картотеке. Проще говоря, пространства имён позволяют сортировать примеси по условным категориям и избегать конфликта их имён. 83 | 84 | Вы можете объявить примесь внутри селектора: 85 | 86 | ```less 87 | .selector { 88 | .mixin(@color: #333) { 89 | color: @color; 90 | } 91 | } 92 | ``` 93 | 94 | При этом основное свойство примеси будет сохраняться, то есть после компиляции примесь не создаст новый класс. Однако, теперь обратиться к примеси с таким объявлением напрямую не получится. Будет выдаваться ошибка. 95 | 96 | В случае, когда указано пространство имён, необходимо указывать полный путь до примеси. 97 | 98 | ```less 99 | // не работает / ошибка (Error: .mixin is undefined) 100 | .class { 101 | .mixin(); 102 | } 103 | 104 | // работает (разные варианты) 105 | .class { 106 | .selector > .mixin(); 107 | .selector .mixin(); 108 | .selector.mixin(); 109 | } 110 | ``` 111 | 112 | Такой подход позволяет создавать примеси, которые не будут конфликтовать с именами других примесей в проекте или используемых библиотеках. 113 | 114 | 115 | 116 | 117 | ## Ключевое слово `!important` 118 | 119 | > Не так давно была выпущена версия компилятора, исправляющая ошибочную работу этого ключевого слова, поэтому перед работой проверьте, что ваш компилятор имеет версию либо ниже `2.3.0`, либо выше. 120 | 121 | Основная суть функции — добавление ко всем свойствам примеси этого ключевого слова. 122 | 123 | ```less 124 | .mixin(@color: #333, @bg: #f5f5f5) { 125 | color: @color; 126 | 127 | .nested { 128 | background-color: @bg; 129 | } 130 | } 131 | 132 | .class { 133 | .mixin() !important; 134 | } 135 | ``` 136 | 137 | После компиляции к каждому свойству будет добавлено ключевое слово `!important`. Причём не важно, будет ли это свойство коренного селектора, либо вложенного. 138 | 139 | ```css 140 | .class { 141 | color: #333333 !important; 142 | } 143 | .class .nested { 144 | background-color: #f5f5f5 !important; 145 | } 146 | ``` 147 | -------------------------------------------------------------------------------- /chapter_2/nested-rules.md: -------------------------------------------------------------------------------- 1 | # Вложенные правила 2 | 3 | В хорошо структурированных таблицах стилей нет необходимости присваивать каждому элементу классы. Достаточно лишь более подробно описывать стили элементов, используя возможность вкладывать селекторы в другие селекторы. К слову, такие селекторы называются **вложенными** и представляют собой объёмную структуру. 4 | 5 | 6 | #### Пример 2.2.1 7 | 8 | Ниже приведён так называемый «подробный CSS», в котором представлена модель вложенности одних селекторов в другие селекторы. 9 | 10 | ```css 11 | .global-header { 12 | background-color: #f5f5f5; 13 | color: #443d3d; 14 | border-bottom: 1px solid #ddd; 15 | } 16 | 17 | .global-header h1 { 18 | margin-top: 0; 19 | margin-bottom: 0; 20 | font-size: 4rem; 21 | } 22 | 23 | .global-header h1 small { 24 | font-size: 2rem; 25 | } 26 | 27 | .global-header .header-actions { 28 | background-color: #fff; 29 | padding-top: 10px; 30 | padding-bottom: 10px; 31 | text-align: center; 32 | } 33 | ``` 34 | 35 | 36 | 37 | 38 | ## Решение проблем 39 | 40 | Все это хорошо, но ровно до тех пор, пока имена классов короткие, глубина вложенности не велика, а ваши глаза в состоянии уследить за этой структурой. Лично я, до тех пор, пока не стал пользоваться CSS-препроцессорами, писал код именно так, попутно разделяя CSS-файл на логические блоки и пытаясь уследить за его чистотой. Это удобно и практично, но мне быстро надоедало сортировать код по вложенности, и моя таблица стилей иногда была похожа на мешанину из букв и цифр. Разумеется, что перед финальной сборкой проекта все это исправлялось, но это не тот случай, на который хочется тратить время. 41 | 42 | Представьте себе оглавление простейшей книги, например, такое: 43 | 44 | ``` 45 | 1. Глава 1. Это моя первая глава книги 46 | 1.1. Это мой первый рассказ о том, что я сделал 47 | 1.1.1. Немного подробнее о том, что я сделал 48 | 1.2. Это мой второй рассказ о том, что я сделал 49 | 1.Х. ... 50 | ``` 51 | 52 | Здесь довольно легко понять, что пункт 1.1 — это следствие первого пункта. Но тем не менее, если переписать это в более читабельном формате, можно сэкономить время на обработке цифр в голове. Абстрактно, можно представить следующий формат: 53 | 54 | ``` 55 | Это моя первая глава книги 56 | Это мой первый рассказ о том, что я сделал 57 | Немного подробнее о том, что я сделал 58 | 59 | Это мой второй рассказ о том, что я сделал 60 | ``` 61 | 62 | Именно такая модель вложенности присутствует в Less, когда один селектор, в прямом смысле слова, вкладывается в другой селектор. Таким образом получается легко поддерживаемая, читаемая и приятная глазу структура. Если же попытаться спроецировать такую модель на CSS-код, то она будет иметь вид: 63 | 64 | ```less 65 | .class-1 { 66 | property: value; 67 | 68 | .class-2 { 69 | property: value; 70 | } 71 | 72 | .class-3 { 73 | property: value; 74 | } 75 | } 76 | ``` 77 | 78 | Для большей наглядности я предлагаю обратиться к конкретному примеру, в котором я постараюсь сопоставить классический CSS и Less код. 79 | 80 | 81 | #### Пример 2.2.2 82 | 83 | Здесь я переписал код из *примера 2.2.1*, заменяя классический синтаксис на препроцессорный. 84 | 85 | ```less 86 | .global-header { 87 | background-color: #f5f5f5; 88 | color: #443d3d; 89 | border-bottom: 1px solid #ddd; 90 | 91 | h1 { 92 | margin-top: 0; 93 | margin-bottom: 0; 94 | font-size: 4rem; 95 | 96 | small { 97 | font-size: 2rem; 98 | } 99 | } 100 | 101 | .header-actions { 102 | background-color: #fff; 103 | padding-top: 10px; 104 | padding-bottom: 10px; 105 | text-align: center; 106 | } 107 | } 108 | ``` 109 | 110 | На изображении ниже представлена модель вложенности, описываемая в этом примере. Для наглядности и понимания сути происходящего экран разделен на две части, где слева код написан на препроцессорном языке, а справа на «чистом» CSS. 111 | 112 | ![](../images/chapter_2_example_222.png) 113 | 114 | 115 | 116 | 117 | ## Мысли и советы 118 | 119 | Согласитесь, теперь ваш код становится интуитивно понятным и удобным для чтения. В такой структуре сложно запутаться и потеряться среди селекторов, ведь здесь чётко видна их вложенность и не нужно помнить имя родительского селектора — за нас это делает компилятор. 120 | 121 | 122 | #### Предостережение! 123 | 124 | Постарайтесь запомнить раз и навсегда, что вкладывать селекторы друг в друга можно бесконечно, но делать это строго **не рекомендуется**! Многие разработчики советуют следить за тем, чтобы структура, в общем случае, не превышала **трёх вложений**. Нет необходимости вкладывать селекторы, начиная от родительского, на такую глубину. Максимально допустимый уровень, в крайних случаях, *пять вложений*. Старайтесь избегать крайних случаев, если это действительно не требуется. 125 | -------------------------------------------------------------------------------- /chapter_3/working-with-rulesets.md: -------------------------------------------------------------------------------- 1 | # Работа с набором правил 2 | 3 | Все те счастливчики, что используют Node.js знают, что без обратного вызова (от англ. callback) невозможно написать приложение. В Less роль функций обратного вызова в примесях берёт на себя **набор правил** (от англ. rule set — блок/набор правил). 4 | 5 | Основная идея набора правил заключается в возможности присвоить переменной не только какое-то значение, но и целый блок кода, состоящий из свойств, селекторов и прочих интересностей. 6 | 7 | На практике это выглядит следующим образом: 8 | 9 | ```less 10 | @element: { 11 | color: #777; 12 | 13 | &.active { 14 | color: #000; 15 | } 16 | }; 17 | 18 | .item { 19 | @element(); 20 | } 21 | ``` 22 | 23 | Такая конструкция напоминает селекторы и, в частности, примеси. Но, надеюсь, в таком ключе использовать её читатель не будет. 24 | 25 | ```css 26 | .item { 27 | color: #777; 28 | } 29 | .item.active { 30 | color: #000; 31 | } 32 | ``` 33 | 34 | За таким поведением переменных стоит другая идея — передача свойств в примеси. Пригодится такая возможность, когда разработчик захочет упростить себе жизнь, написав пару примесей. Например, разработчику надоело писать длинные медиавыражения или он решил ограничить область видимости переменных. 35 | 36 | Рассмотрим пример, иллюстрирующий преимущество использования набора правил. 37 | 38 | 39 | 40 | 41 | ## Набор правил как функция обратного вызова 42 | 43 | В случае с медиавыражениями понятно: нужно всего лишь описать заранее само выражение и передавать туда необходимые свойства и селекторы. 44 | 45 | > Представленный здесь код доступен как пример 3.7.1. 46 | 47 | ```less 48 | .screen(@min, @max, @ruleset) { 49 | @media (min-width: @min) and (max-width: (@max - 1)) { 50 | @ruleset(); 51 | } 52 | } 53 | ``` 54 | 55 | Теперь при вызове такой примеси ему нужно передать два размера экрана и набор правил. При компиляции вместо переменной `@ruleset` будут подставлены те значения, что были переданы при вызове в фигурных скобках. 56 | 57 | ```less 58 | .class { 59 | background-color: #000; 60 | 61 | .screen(768px, 1200px, { 62 | background-color: #fff; 63 | }); 64 | } 65 | ``` 66 | 67 | После компиляции получим следующий CSS-код: 68 | 69 | ```css 70 | .class { 71 | background-color: #000; 72 | } 73 | @media (min-width: 768px) and (max-width: 1199px) { 74 | .class { 75 | background-color: #fff; 76 | } 77 | } 78 | ``` 79 | 80 | Для наглядности посмотрите на callback в JavaScript и сравните получившуюся у нас примесь с ним. 81 | 82 | Объявление и вызов: 83 | 84 | ```js 85 | function mySandwich(param1, param2, callback) { 86 | console.log('Мой сэндвич включает в себя ' + param1 + ' и ' + param2 + '.'); 87 | callback(); 88 | } 89 | 90 | mySandwich('котлету', 'сыр', function() { 91 | console.log('А также соус, огурцы и прочие вкусняшки.'); 92 | }); 93 | ``` 94 | 95 | В консоль выведется: 96 | 97 | ``` 98 | Мой сэндвич включает в себя котлету и сыр. 99 | А также соус, огурцы и прочие вкусняшки. 100 | ``` 101 | 102 | Если посмотреть на функцию обратного вызова в Less и JavaScript, то несложно заметить их сходство. Для тех, кто знаком с Node.js — это поможет понять сущность набора правил в Less, благодаря проведению параллели между Less и JavaScript. Тем же, кто не знаком с JavaScript, есть куда стремиться. 103 | 104 | 105 | 106 | 107 | ## Набор правил как область видимости 108 | 109 | > Представленный здесь код доступен как пример 3.7.2. 110 | 111 | Обратите внимание на следующий код: 112 | 113 | ```less 114 | @variable: global; 115 | 116 | @detached-ruleset: { 117 | variable: @variable; 118 | }; 119 | 120 | selector { 121 | @detached-ruleset(); 122 | @variable: value; 123 | } 124 | ``` 125 | 126 | На первый взгляд свойство `variable` будет иметь значение `value`, так как здесь будет действовать правило ленивой загрузки переменных. Однако, так как мы имеет дело с набором правил, свойству будет присвоено значение `global`. 127 | 128 | ```css 129 | selector { 130 | variable: global; 131 | } 132 | ``` 133 | 134 | Происходит это из-за того, что переменная `@variable` локальная для селектора `selector`, а переменная, содержащая вызов этой переменной объявлена глобально, следовательно, изначально поиск значения переменной будет происходить в глобальной области, а потом уже в локальной области. 135 | 136 | Если же убрать глобальную переменную `@variable`: 137 | 138 | ```less 139 | @detached-ruleset: { 140 | variable: @variable; 141 | }; 142 | 143 | selector { 144 | @detached-ruleset(); 145 | @variable: value; 146 | } 147 | ``` 148 | 149 | то значение будет браться от локальной переменной: 150 | 151 | ```css 152 | selector { 153 | variable: value 154 | } 155 | ``` 156 | 157 | > Другие интересные примеры применения области видимости, в случае использования набора правил, вы можете найти в официальной документации. Вызвано это тем, что они очень похожи друг на друга, а раздувать объяснение похожих примеров — не особо интересное занятие. 158 | 159 | 160 | 161 | 162 | ## Мысли и советы 163 | 164 | Не используйте переменные с набором правил как примеси. Машины созданы для того, чтобы ездить, а самолёты, чтобы летать. 165 | 166 | Основная задача переменных с набором правил — передача свойств в примеси. Старайтесь использовать эту возможность именно так, и никак иначе. 167 | -------------------------------------------------------------------------------- /examples/chapter_2/homework/styles.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | html { 3 | font-family: sans-serif; 4 | -ms-text-size-adjust: 100%; 5 | -webkit-text-size-adjust: 100%; 6 | } 7 | body { 8 | margin: 0; 9 | } 10 | article, 11 | aside, 12 | details, 13 | figcaption, 14 | figure, 15 | footer, 16 | header, 17 | hgroup, 18 | main, 19 | menu, 20 | nav, 21 | section, 22 | summary { 23 | display: block; 24 | } 25 | audio, 26 | canvas, 27 | progress, 28 | video { 29 | display: inline-block; 30 | vertical-align: baseline; 31 | } 32 | audio:not([controls]) { 33 | display: none; 34 | height: 0; 35 | } 36 | [hidden], 37 | template { 38 | display: none; 39 | } 40 | a { 41 | background-color: transparent; 42 | } 43 | a:active, 44 | a:hover { 45 | outline: 0; 46 | } 47 | abbr[title] { 48 | border-bottom: 1px dotted; 49 | } 50 | b, 51 | strong { 52 | font-weight: bold; 53 | } 54 | dfn { 55 | font-style: italic; 56 | } 57 | h1 { 58 | font-size: 2em; 59 | margin: 0.67em 0; 60 | } 61 | mark { 62 | background: #ff0; 63 | color: #000; 64 | } 65 | small { 66 | font-size: 80%; 67 | } 68 | sub, 69 | sup { 70 | font-size: 75%; 71 | line-height: 0; 72 | position: relative; 73 | vertical-align: baseline; 74 | } 75 | sup { 76 | top: -0.5em; 77 | } 78 | sub { 79 | bottom: -0.25em; 80 | } 81 | img { 82 | border: 0; 83 | } 84 | svg:not(:root) { 85 | overflow: hidden; 86 | } 87 | figure { 88 | margin: 1em 40px; 89 | } 90 | hr { 91 | -moz-box-sizing: content-box; 92 | box-sizing: content-box; 93 | height: 0; 94 | } 95 | pre { 96 | overflow: auto; 97 | } 98 | code, 99 | kbd, 100 | pre, 101 | samp { 102 | font-family: monospace, monospace; 103 | font-size: 1em; 104 | } 105 | button, 106 | input, 107 | optgroup, 108 | select, 109 | textarea { 110 | color: inherit; 111 | font: inherit; 112 | margin: 0; 113 | } 114 | button { 115 | overflow: visible; 116 | } 117 | button, 118 | select { 119 | text-transform: none; 120 | } 121 | button, 122 | html input[type="button"], 123 | input[type="reset"], 124 | input[type="submit"] { 125 | -webkit-appearance: button; 126 | cursor: pointer; 127 | } 128 | button[disabled], 129 | html input[disabled] { 130 | cursor: default; 131 | } 132 | button::-moz-focus-inner, 133 | input::-moz-focus-inner { 134 | border: 0; 135 | padding: 0; 136 | } 137 | input { 138 | line-height: normal; 139 | } 140 | input[type="checkbox"], 141 | input[type="radio"] { 142 | box-sizing: border-box; 143 | padding: 0; 144 | } 145 | input[type="number"]::-webkit-inner-spin-button, 146 | input[type="number"]::-webkit-outer-spin-button { 147 | height: auto; 148 | } 149 | input[type="search"] { 150 | -webkit-appearance: textfield; 151 | -moz-box-sizing: content-box; 152 | -webkit-box-sizing: content-box; 153 | box-sizing: content-box; 154 | } 155 | input[type="search"]::-webkit-search-cancel-button, 156 | input[type="search"]::-webkit-search-decoration { 157 | -webkit-appearance: none; 158 | } 159 | fieldset { 160 | border: 1px solid #c0c0c0; 161 | margin: 0 2px; 162 | padding: 0.35em 0.625em 0.75em; 163 | } 164 | legend { 165 | border: 0; 166 | padding: 0; 167 | } 168 | textarea { 169 | overflow: auto; 170 | } 171 | optgroup { 172 | font-weight: bold; 173 | } 174 | table { 175 | border-collapse: collapse; 176 | border-spacing: 0; 177 | } 178 | td, 179 | th { 180 | padding: 0; 181 | } 182 | *:before, 183 | *:after { 184 | box-sizing: border-box; 185 | } 186 | html { 187 | font-size: 10px; 188 | } 189 | body { 190 | font-size: 14px; 191 | line-height: 20px; 192 | font-family: Lucida Grande, Arial, tahoma, verdana, sans-serif; 193 | font-weight: normal; 194 | } 195 | .clearfix:before, 196 | .clearfix:after, 197 | .container:before, 198 | .container:after, 199 | .gallery-list:before, 200 | .gallery-list:after { 201 | content: " "; 202 | display: table; 203 | } 204 | .clearfix:after, 205 | .container:after, 206 | .gallery-list:after { 207 | clear: both; 208 | } 209 | h1, 210 | h2, 211 | h3, 212 | h4, 213 | h5, 214 | h6 { 215 | margin-top: 0; 216 | margin-bottom: 0; 217 | } 218 | h1 { 219 | font-weight: 300; 220 | line-height: 1.25; 221 | font-size: 3.2rem; 222 | } 223 | ul { 224 | margin: 0; 225 | padding: 0; 226 | list-style: none; 227 | } 228 | img { 229 | display: block; 230 | max-width: 100%; 231 | height: auto; 232 | } 233 | .container { 234 | position: relative; 235 | margin-left: auto; 236 | margin-right: auto; 237 | } 238 | @media (min-width: 768px) { 239 | .container { 240 | width: 750px; 241 | } 242 | } 243 | @media (min-width: 992px) { 244 | .container { 245 | width: 970px; 246 | } 247 | } 248 | .page-title { 249 | background-color: #ecf0f1; 250 | padding: 50px 10px; 251 | text-align: center; 252 | } 253 | .gallery-slider { 254 | background-color: #bdc3c7; 255 | padding-top: 35px; 256 | padding-bottom: 35px; 257 | } 258 | @media (min-width: 540px) { 259 | .gallery-list li { 260 | width: 50%; 261 | float: left; 262 | } 263 | } 264 | @media (min-width: 768px) { 265 | .gallery-list li { 266 | width: 33.33333%; 267 | } 268 | } 269 | @media (min-width: 992px) { 270 | .gallery-list li { 271 | width: 20%; 272 | } 273 | } 274 | .gallery-list a { 275 | display: block; 276 | margin: 10px; 277 | } 278 | .gallery-list a:hover, 279 | .gallery-list a:focus { 280 | opacity: .5; 281 | } 282 | .gallery-list img { 283 | margin-left: auto; 284 | margin-right: auto; 285 | } 286 | -------------------------------------------------------------------------------- /examples/chapter_3/homework/styles.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | html { 3 | font-family: sans-serif; 4 | -ms-text-size-adjust: 100%; 5 | -webkit-text-size-adjust: 100%; 6 | } 7 | body { 8 | margin: 0; 9 | } 10 | article, 11 | aside, 12 | details, 13 | figcaption, 14 | figure, 15 | footer, 16 | header, 17 | hgroup, 18 | main, 19 | menu, 20 | nav, 21 | section, 22 | summary { 23 | display: block; 24 | } 25 | audio, 26 | canvas, 27 | progress, 28 | video { 29 | display: inline-block; 30 | vertical-align: baseline; 31 | } 32 | audio:not([controls]) { 33 | display: none; 34 | height: 0; 35 | } 36 | [hidden], 37 | template { 38 | display: none; 39 | } 40 | a { 41 | background-color: transparent; 42 | } 43 | a:active, 44 | a:hover { 45 | outline: 0; 46 | } 47 | abbr[title] { 48 | border-bottom: 1px dotted; 49 | } 50 | b, 51 | strong { 52 | font-weight: bold; 53 | } 54 | dfn { 55 | font-style: italic; 56 | } 57 | h1 { 58 | font-size: 2em; 59 | margin: 0.67em 0; 60 | } 61 | mark { 62 | background: #ff0; 63 | color: #000; 64 | } 65 | small { 66 | font-size: 80%; 67 | } 68 | sub, 69 | sup { 70 | font-size: 75%; 71 | line-height: 0; 72 | position: relative; 73 | vertical-align: baseline; 74 | } 75 | sup { 76 | top: -0.5em; 77 | } 78 | sub { 79 | bottom: -0.25em; 80 | } 81 | img { 82 | border: 0; 83 | } 84 | svg:not(:root) { 85 | overflow: hidden; 86 | } 87 | figure { 88 | margin: 1em 40px; 89 | } 90 | hr { 91 | -moz-box-sizing: content-box; 92 | box-sizing: content-box; 93 | height: 0; 94 | } 95 | pre { 96 | overflow: auto; 97 | } 98 | code, 99 | kbd, 100 | pre, 101 | samp { 102 | font-family: monospace, monospace; 103 | font-size: 1em; 104 | } 105 | button, 106 | input, 107 | optgroup, 108 | select, 109 | textarea { 110 | color: inherit; 111 | font: inherit; 112 | margin: 0; 113 | } 114 | button { 115 | overflow: visible; 116 | } 117 | button, 118 | select { 119 | text-transform: none; 120 | } 121 | button, 122 | html input[type="button"], 123 | input[type="reset"], 124 | input[type="submit"] { 125 | -webkit-appearance: button; 126 | cursor: pointer; 127 | } 128 | button[disabled], 129 | html input[disabled] { 130 | cursor: default; 131 | } 132 | button::-moz-focus-inner, 133 | input::-moz-focus-inner { 134 | border: 0; 135 | padding: 0; 136 | } 137 | input { 138 | line-height: normal; 139 | } 140 | input[type="checkbox"], 141 | input[type="radio"] { 142 | box-sizing: border-box; 143 | padding: 0; 144 | } 145 | input[type="number"]::-webkit-inner-spin-button, 146 | input[type="number"]::-webkit-outer-spin-button { 147 | height: auto; 148 | } 149 | input[type="search"] { 150 | -webkit-appearance: textfield; 151 | -moz-box-sizing: content-box; 152 | -webkit-box-sizing: content-box; 153 | box-sizing: content-box; 154 | } 155 | input[type="search"]::-webkit-search-cancel-button, 156 | input[type="search"]::-webkit-search-decoration { 157 | -webkit-appearance: none; 158 | } 159 | fieldset { 160 | border: 1px solid #c0c0c0; 161 | margin: 0 2px; 162 | padding: 0.35em 0.625em 0.75em; 163 | } 164 | legend { 165 | border: 0; 166 | padding: 0; 167 | } 168 | textarea { 169 | overflow: auto; 170 | } 171 | optgroup { 172 | font-weight: bold; 173 | } 174 | table { 175 | border-collapse: collapse; 176 | border-spacing: 0; 177 | } 178 | td, 179 | th { 180 | padding: 0; 181 | } 182 | *:before, 183 | *:after { 184 | box-sizing: border-box; 185 | } 186 | html { 187 | font-size: 10px; 188 | } 189 | body { 190 | font-size: 14px; 191 | line-height: 20px; 192 | font-family: Lucida Grande, Arial, tahoma, verdana, sans-serif; 193 | font-weight: normal; 194 | } 195 | .clearfix:before, 196 | .clearfix:after, 197 | .container:before, 198 | .container:after { 199 | content: " "; 200 | display: table; 201 | } 202 | .clearfix:after, 203 | .container:after { 204 | clear: both; 205 | } 206 | h1, 207 | h2, 208 | h3, 209 | h4, 210 | h5, 211 | h6 { 212 | margin-top: 2em; 213 | margin-bottom: 1em; 214 | } 215 | h1 { 216 | font-weight: 300; 217 | line-height: 1.25; 218 | font-size: 3.2rem; 219 | } 220 | .container { 221 | position: relative; 222 | margin-left: auto; 223 | margin-right: auto; 224 | } 225 | @media (min-width: 768px) { 226 | .container { 227 | width: 750px; 228 | } 229 | } 230 | @media (min-width: 992px) { 231 | .container { 232 | width: 970px; 233 | } 234 | } 235 | .btn { 236 | display: inline-block; 237 | cursor: pointer; 238 | user-select: none; 239 | text-align: center; 240 | vertical-align: middle; 241 | white-space: nowrap; 242 | border: 1px solid transparent; 243 | border-radius: 4px; 244 | outline: none; 245 | background-image: none; 246 | touch-action: manipulation; 247 | font-size: 14px; 248 | padding: 6px 12px; 249 | } 250 | .btn-default { 251 | background-color: #e0e0e0; 252 | color: #333333; 253 | } 254 | .btn-default:focus, 255 | .btn-default:hover, 256 | .btn-default.active { 257 | background-color: #e8e8e8; 258 | color: #333333; 259 | } 260 | .btn-info { 261 | background-color: #3b83c0; 262 | color: #ffffff; 263 | } 264 | .btn-info:focus, 265 | .btn-info:hover, 266 | .btn-info.active { 267 | background-color: #458ac6; 268 | color: #ffffff; 269 | } 270 | .btn-secondary { 271 | background-color: #404245; 272 | color: #ffffff; 273 | } 274 | .btn-secondary:focus, 275 | .btn-secondary:hover, 276 | .btn-secondary.active { 277 | background-color: #1b1c1d; 278 | color: #ffffff; 279 | } 280 | .btn-xs { 281 | font-size: 10px; 282 | padding: 2px 4px; 283 | } 284 | .btn-xl { 285 | font-size: 18px; 286 | padding: 10px 16px; 287 | } 288 | -------------------------------------------------------------------------------- /chapter_6/working-with-variables-and-mixins.md: -------------------------------------------------------------------------------- 1 | # Работа с переменными и примесями 2 | 3 | Чтобы компилятор выполнял хоть сколько-нибудь полезные действия, интерпретируя JavaScript-код — ему нужны значения, которые он может получить из переменных. Для того, чтобы получить значения переменных, необходимо использовать один из представленных ниже вариантов синтаксиса: 4 | 5 | ```less 6 | .test-js { 7 | @test: 123; 8 | content: `@{test}`; 9 | content: `this.test.toJS()`; 10 | } 11 | ``` 12 | 13 | Оба варианта хорошо работают с локальными переменными. С глобальными переменными работает лишь первый способ, так как `this`, во втором случае, явно указывает на контекст, то есть селектор. Без контекста `test.toJS()` работать не будет. 14 | 15 | Результатом компиляции будет: 16 | 17 | ```css 18 | .test-js { 19 | content: 123; 20 | content: "123"; 21 | } 22 | ``` 23 | 24 | Далее я приведу несколько примеров работы с переменными, используя JavaScript-код в Less: 25 | 26 | ```less 27 | .test-js { 28 | // Интерполяция 29 | @world: "world"; 30 | content: ~`'hello' + ' ' + @{world}`; 31 | 32 | // Списки 33 | @list: 1, 2, 3; 34 | @list-js: ~`@{list}.join(', ')`; 35 | content: @list-js; 36 | } 37 | ``` 38 | 39 | Компилятор создаст два свойства `content` и присвоит им вполне валидные значения: 40 | 41 | ```css 42 | .test-js { 43 | content: hello world; 44 | content: 1, 2, 3; 45 | } 46 | ``` 47 | 48 | Первый пример демонстрирует возможность интерполяции строк прямиком в JavaScript, второй — работу со списками. 49 | 50 | Немного подробнее остановимся на списках. Ранее я уже говорил, что списки — это альтернатива массивам в JavaScript. Списки в Less можно итерировать и узнавать их длину. Тот список, что определён в переменной `@list` никаких вопросов не вызывает: 51 | 52 | ```less 53 | .test-js { 54 | @list: 1, 2, 3; 55 | content: length(@list); 56 | content: extract(@list, 1); 57 | } 58 | 59 | // На выходе получаем 60 | .test-js { 61 | content: 3; // Длина 62 | content: 1; // Первый элемент массива 63 | } 64 | ``` 65 | 66 | А вот значение переменной `@list-js` списком не является, так как на выходе JavaScript-кода всегда находится строка: 67 | 68 | ```less 69 | .test-js { 70 | @list: 1, 2, 3; 71 | @list-js: ~`@{list}.join(', ')`; 72 | content: length(@list-js); 73 | content: extract(@list-js, 1); 74 | } 75 | 76 | // На выходе получаем 77 | .test-js { 78 | content: 1; // Длина 79 | content: 1, 2, 3; // Первый элемент массива 80 | } 81 | ``` 82 | 83 | 84 | 85 | 86 | ## Примеси 87 | 88 | Наиболее очевидным применением возможностей JavaScript-кода в Less является создание примесей, которые на вход получают какое-то количество переменных, обрабатывают их, используя JavaScript и возвращают строку, как результат. 89 | 90 | 91 | 92 | ### Конечное число переменных 93 | 94 | Самым простым способом получить значения из переменных в Less является следующая функция: 95 | 96 | ```js 97 | (function(a, b) { 98 | return a + b; 99 | })('@{a}', '@{b}') 100 | ``` 101 | 102 | Используя обёртку в виде примеси, её можно представить в удобном для использования виде: 103 | 104 | ```less 105 | .mixin(@a, @b) { 106 | @js: ~`(function(a, b) { return a + b; })('@{a}', '@{b}')`; 107 | 108 | content: @js; 109 | } 110 | 111 | .test-js { 112 | .mixin(1, 2); 113 | } 114 | ``` 115 | 116 | Результатом компиляции будет являться сумма двух чисел, переданных, как аргументы примеси `.mixin()`: 117 | 118 | ```css 119 | .test-js { 120 | content: 12; 121 | } 122 | ``` 123 | 124 | 125 | 126 | ### Неопределённое число переменных 127 | 128 | Если для проведения операций в выражении требуется большое количество переменных, или их количество неизвестно заранее, то на помощь приходит следующая функция, возвращающая массив всех переданных аргументов: 129 | 130 | ```js 131 | (function(args) { 132 | return args; 133 | })('@{arguments}') 134 | ``` 135 | 136 | Записывая эту функцию в переменную и используя примесь, у которой на вход подаётся переменное количество аргументов, получим следующий less-код: 137 | 138 | ```less 139 | .mixin(...) { 140 | @js: ~`(function(args){ return args; })('@{arguments}')`; 141 | 142 | content: @js; 143 | } 144 | 145 | .test-js { 146 | .mixin(3, 123); 147 | } 148 | ``` 149 | 150 | И, как я уже сказал, после компиляции будет доступен массив всех переданных значений: 151 | 152 | ```css 153 | .test-js { 154 | content: [3, 123]; 155 | } 156 | ``` 157 | 158 | В Less с таким результатом сделать ничего не получится (мешают квадратные скобки), поэтому на практике лучше всего использовать следующую модификацию предложенной функции: 159 | 160 | ```js 161 | (function(args) { 162 | return args; 163 | })((function() { 164 | var args = '@{arguments}'; 165 | return args.replace(/^\[|\]$/g, '') 166 | })()) 167 | ``` 168 | 169 | Этот вариант записи удаляет квадратные скобки, используя метод `replace()`, при этом делая получаемый на выходе массив немного лучше: 170 | 171 | ```less 172 | .mixin(...) { 173 | @js: ~`function(args){return args}(function(){var args='@{arguments}';return args.replace(/^\[|\]$/g,'')}())`; 174 | 175 | content: @js; 176 | } 177 | 178 | .test-js { 179 | .mixin(3, 123); 180 | } 181 | ``` 182 | 183 | К сожалению, как я и показывал ранее — массив преобразуется в строку, содержимое которой нельзя итерировать. 184 | 185 | ```css 186 | .test-js { 187 | content: 3, 123; 188 | } 189 | ``` 190 | 191 | 192 | 193 | 194 | ## Преобразование значений 195 | 196 | Конечно, на практике мало пользы от того, что вы можете получить, распарсить и отдать результат обратно — необходимо с ним как-то взаимодействовать. 197 | 198 | В приведённом ниже примере последнему в списке значению добавляется единица измерения `deg`: 199 | 200 | ```js 201 | (function(args) { 202 | return args = args || '0, 0, 0, 0', args = args.replace(/,\s*\d+$/, function(args) { 203 | return args + 'deg' 204 | }) 205 | })((function() { 206 | var args = '@{arguments}'; 207 | return args = args.replace(/^\[|\]$/g, '') 208 | })()) 209 | ``` 210 | 211 | В итоге примесь имеет вид: 212 | 213 | ```less 214 | .rotate3d(...) { 215 | @js: ~`(function(args) { return args = args || '0, 0, 0, 0', args = args.replace(/,\s*\d+$/, function(args) { return args + 'deg' }) })((function() { var args = '@{arguments}'; return args = args.replace(/^\[|\]$/g, '') })())`; 216 | 217 | transform: rotate3d(@js); 218 | } 219 | 220 | .test-js { 221 | .rotate3d(1, 0, 0, 50); 222 | } 223 | ``` 224 | 225 | После компиляции получится отформатированное значение свойства `transform`: 226 | 227 | ```css 228 | .test-js { 229 | transform: rotate3d(1, 0, 0, 50deg); 230 | } 231 | ``` 232 | 233 | Если вызвать эту же примесь без аргументов, то будет выводиться результат по умолчанию, то есть нули: 234 | 235 | ```css 236 | .test-js { 237 | transform: rotate3d(0, 0, 0, 0deg); 238 | } 239 | ``` 240 | 241 | > Описанные в этой главе примеры доступны под номерами 6.1.1 - 6.1.4 и работают только с компиляторами, написанными на JavaScript. 242 | 243 | 244 | 245 | 246 | ## Выводы и мысли 247 | 248 | Да, Less умеет интерпретировать JavaScript-код, записанный в переменной или в значении свойства, но получаемая от этого польза слишком мала и не покрывает потраченных на это усилий. Используя JavaScript в Less вы загрязняете его и усложняете для восприятия. 249 | -------------------------------------------------------------------------------- /chapter_5/if.md: -------------------------------------------------------------------------------- 1 | # Условные конструкции (защита примесей) 2 | 3 | Условная конструкция — это самая часто используемая почти во всех языках программирования инструкция, к сожалению, отсутствующая в явном виде в Less. 4 | 5 | Обычно, различают три вида условных конструкций по количеству ветвей: одно-, дву- и многоветвевую. 6 | 7 | В JavaScript очень часто встречаются двуветвевые условные конструкции, где в зависимости от результата выражения выполняется тот или иной блок (true или false): 8 | 9 | ```js 10 | if (выражение) { 11 | // True 12 | } else { 13 | // False 14 | } 15 | ``` 16 | 17 | 18 | 19 | 20 | ## Ситуация в Less 21 | 22 | В Less нет такого понятия, как условная конструкция. Здесь оперируют понятием — защита примесей. Ниже представлен обычный `if`: 23 | 24 | ```less 25 | .mixin(@a, @b) when (выражение) { 26 | // True 27 | } 28 | ``` 29 | 30 | Примесь будет выполняться только тогда, когда выражение, указанное после ключевого слова `when` будет истинно. 31 | 32 | 33 | 34 | ### Операторы отношений 35 | 36 | Операторы отношений: «меньше» (`<`), «больше» (`>`), «меньше или равно» (`=<` или `<=`),«больше или равно» (`>=`) и «равно» (`=`) сравнивают значения так же, как и в JavaScript. Каждый из них возвращает логическое значение. 37 | 38 | > **Замечание** 39 | > 40 | > Оператор отношения «меньше или равно» (`=<` или `<=`) отличается от аналогичного в JavaScript, где его запись имеет только один вид (`<=`). В соответствии с документацией принято использовать (`=<`). 41 | 42 | 43 | 44 | ### Логическое НЕ, И и ИЛИ 45 | 46 | Условия могут содержать ключевое слово `not`, являющееся аналогом привычного нам по JavaScript отрицания `!`. 47 | 48 | Например, следующая примесь будет выполняться, если переданное ей значение `@value` не равно нулю. 49 | 50 | ```less 51 | .mixin(@value) when not (@value = 0) { 52 | color: #777; 53 | } 54 | ``` 55 | 56 | Также, условия можно объединять, создавая более конкретные условия. Для этого используется ключевое слово `and`. 57 | 58 | ```less 59 | .mixin(@value) when (@value > 0) and (@value =< 100) { 60 | color: #777; 61 | } 62 | ``` 63 | 64 | Ключевое слово `and` можно опускать, используя взамен запятую: 65 | 66 | ```less 67 | .mixin(@value) when (@value > 0), (@value =< 100) { 68 | color: #777; 69 | } 70 | ``` 71 | 72 | Начиная с версии **2.6.0** компилятор поддерживает ключевое слово `or`, соответствующее логическому «ИЛИ». Синтаксис повторяет синтаксис ключевого слова `and`, но никаких синонимов взамен не предлагает (у `and` синонимом является запятая): 73 | 74 | ```less 75 | .mixin(@value) when (@value > 0) or (@value = -1) { 76 | content: @value; 77 | } 78 | ``` 79 | 80 | > **Замечание** 81 | > 82 | > Логический оператор `and` имеет больший приоритет, чем логический оператор `or`, как и в любом языке программирования. 83 | 84 | Помимо написанных вручную условий, можно использовать некоторые встроенные функции для проверки величин на совпадение с различными типами и размерностями. 85 | 86 | 87 | 88 | ### Работа с типами данных 89 | 90 | В главе 4 были рассмотрены функции для определения типа данных, которыми оперирует пользователь препроцессора Less. Все эти функции можно использовать в условном операторе. Причём важно отметить, что Less автоматически преобразует результат выражения в логическое значение, как это делает JavaScript, вызывая для него функцию `Boolean()`. 91 | 92 | Так, например, рассмотренная ранее функция `isnumber()`, проверяющая являются ли предоставленные ей данные числом, может применяться следующим образом: 93 | 94 | ```less 95 | .return-number(@number) when (isnumber(@number)) { 96 | content: @number; 97 | } 98 | 99 | .true { 100 | .return-number(123); 101 | } 102 | 103 | .false { 104 | .return-number("123"); 105 | } 106 | ``` 107 | 108 | В первом случае будет создан селектор `.true`, так как значение, передаваемое в примесь, является числом. Во втором же случае, передаваемое значение — строка, что означает `false`. 109 | 110 | 111 | 112 | ### Конструкция `if {} else {}` 113 | 114 | С помощью ключевого слова `default()` можно определить примесь по умолчанию, которая будет выполняться при условии, что другие примеси не сработали. 115 | 116 | ```less 117 | .mixin(@a, @b) when (@a > @b) { 118 | content: if; 119 | } 120 | 121 | .mixin(@a, @b) when (default()) { 122 | content: else; 123 | } 124 | ``` 125 | 126 | Вызовем примесь `mixin` с параметрами (3, 1). В этом случае выполняется первая примесь, потому что введённые данные подходят под указанное в ней выражение (3 больше чем 1). 127 | 128 | Если вызвать эту же примесь с параметрами (1, 1), то выполнится вторая примесь, так как выражение первой примеси вернуло `false`. 129 | 130 | 131 | 132 | ### Конструкция `if {} else if {} else {}` 133 | 134 | Ситуация полностью аналогична предыдущей, с той лишь разницей, что примесей будет три: 135 | 136 | ```less 137 | .mixin(@a, @b) when (@a > @b) { 138 | content: if; 139 | } 140 | 141 | .mixin(@a, @b) when (@a < @b) { 142 | content: else if; 143 | } 144 | 145 | .mixin(@a, @b) when (default()) { 146 | content: else; 147 | } 148 | ``` 149 | 150 | Теперь условная конструкция выводит `if`, если *a* больше *b*, `else if`, если *a* меньше *b*, иначе `else`. 151 | 152 | 153 | #### Пример 5.1.1 154 | 155 | Разберём работу примеси, которая генерирует внутренние отступы блока по правилу: 156 | 157 | * Если указан один параметр, то генерировать свойство с одним значением. 158 | * Если указано два параметра, то генерировать свойство с двумя значениями. 159 | * и т.д. 160 | 161 | Итак, необходимо использовать значения по умолчанию для того, чтобы не приходилось каждый раз указывать значения для всех параметров: 162 | 163 | ```less 164 | .padding(@t: none, @r: none, @b: none, @l: none) { 165 | 166 | } 167 | ``` 168 | 169 | Теперь можно приступить к написанию условий: 170 | 171 | ```less 172 | .padding(@t: none, @r: none, @b: none, @l: none) { 173 | & when not (@t = none) { padding+_: @t; } 174 | & when not (@r = none) { padding+_: @r; } 175 | & when not (@b = none) { padding+_: @b; } 176 | & when not (@l = none) { padding+_: @l; } 177 | } 178 | ``` 179 | 180 | Здесь использовалась возможность слияния значения свойств, которая обсуждалось в главе 4. 181 | 182 | В итоге мы имеем примесь, которая выводит: 183 | 184 | ```less 185 | .padding(1px) // padding: 1px; 186 | .padding(1px, 2px) // padding: 1px 2px; 187 | ... 188 | ``` 189 | 190 | 191 | 192 | ### Примеси как функции и условные конструкции 193 | 194 | Следует аккуратно использовать сокращённую запись условной конструкции, которая имеет вид: 195 | 196 | ```less 197 | .mixin(@a) { 198 | & when (@a = 1) { 199 | @return: value; 200 | } 201 | } 202 | ``` 203 | 204 | Если вызвать эту примесь сейчас с параметром 1 и попытаться получить значение переменной `@return`, то компилятор выдаст ошибку, говорящую о том, что такой переменной нет: 205 | 206 | ```less 207 | .test { 208 | .mixin(1); 209 | content: @return; 210 | } 211 | ``` 212 | 213 | Ошибка имеет вид: 214 | 215 | ``` 216 | NameError: variable @return is undefined in 217 | C:\...\a.test on line 9, column 12: 218 | 8 .mixin(1); 219 | 9 content: @return; 220 | 10 } 221 | ``` 222 | 223 | Кстати, вы заметили, что я создал файл с расширением `.test`, и компилятор корректно его обработал? Напомню, что это обсуждалось в главе 1 (Импорт стилей в Less). 224 | 225 | Связано это с тем, что ссылка на родительский селектор (&) создаёт новую область видимости. Подробнее об этом в главе 3 в разделе «Области видимости». 226 | 227 | В тоже время, если использовать полную запись, то ошибки не будет: 228 | 229 | ```less 230 | .mixin(@a) when (@a = 1) { 231 | @return: value; 232 | } 233 | 234 | .test { 235 | .mixin(1); 236 | content: @return; 237 | } 238 | ``` 239 | 240 | Этот код будет генерировать селектор `.test` со свойством `content`, имеющим значение переменной `@return`. 241 | -------------------------------------------------------------------------------- /chapter_3/using-mixins.md: -------------------------------------------------------------------------------- 1 | # Использование примесей 2 | 3 | Когда-то давно, наверное, только ленивый разработчик не мечтал о переиспользуемом CSS-коде. Вы только представьте себе то, что какой-нибудь блок кода может быть вызван повторно, и все его свойства станут доступны и второму селектору. Тогда это были желания, сейчас же это реальность. 4 | 5 | В отличие от других CSS-препроцессоров, в Less любой объявленный селектор может использоваться как примесь. **Примесь** (от англ. mix-in) — набор свойств и селекторов, расширяющий поведение другой сущности (селектора). 6 | 7 | Рассмотрим типичное объявление, которое уже миллионы раз встречалось в вашем CSS-коде: 8 | 9 | ```less 10 | .bordered { 11 | border-top: dotted 1px #333; 12 | border-bottom: solid 2px #333; 13 | } 14 | ``` 15 | 16 | Казалось бы, ничего необычного, но ровно до тех пор, пока не сделать следующее: 17 | 18 | ```less 19 | .article { 20 | .bordered; 21 | color: #443d3d; 22 | } 23 | ``` 24 | 25 | После компиляции селектор `.bordered` безвозмездно отдаст все свои свойства и вложенные правила селектору `.article`. При этом в конечном CSS-файле будут объявлены оба этих селектора. 26 | 27 | ```css 28 | .bordered { 29 | border-top: dotted 1px #333; 30 | border-bottom: solid 2px #333; 31 | } 32 | .article { 33 | border-top: dotted 1px #333; 34 | border-bottom: solid 2px #333; 35 | color: #443d3d; 36 | } 37 | ``` 38 | 39 | На самом деле, такая запись практически не используется на практике и не называется примесью. Настоящая примесь — она какая-то другая, волшебная. Но различие в них настолько мало, что и заметить бывает сложно: 40 | 41 | ```less 42 | .bordered() { 43 | border-top: dotted 1px #333; 44 | border-bottom: solid 2px #333; 45 | } 46 | 47 | .article { 48 | .bordered; 49 | color: #443d3d; 50 | } 51 | ``` 52 | 53 | В этой записи я добавил скобки после селектора `.bordered`, и уже сейчас он может гордо носить название примеси. В этом случае при компиляции не будет создан класс `.bordered`, так как у него указаны скобки после имени. Такая конструкция говорит компилятору, что она чистейшая примесь, которая не хочет быть скомпилирована без явных на то причин. 54 | 55 | ```css 56 | .article { 57 | border-top: dotted 1px #333; 58 | border-bottom: solid 2px #333; 59 | color: #443d3d; 60 | } 61 | ``` 62 | 63 | Неважно, будут ли указаны скобки при вызове примеси (`.bordered();`) или нет (`.bordered;`) — результат будет одинаковым. Однако, я бы советовал их указывать из-за того, что примеси могут иметь параметры. 64 | 65 | 66 | 67 | 68 | ## Примеси с параметрами 69 | 70 | Для того, чтобы примеси были переиспользуемыми в различных контекстах, у них могут быть указаны параметры, в зависимости от которых может меняться цвет, фон и другие значения. Параметры указываются в скобках после имени примеси и представляют собой обычные локальные переменные. 71 | 72 | ```less 73 | .bordered(@_color) { 74 | border-top: dotted 1px @_color; 75 | border-bottom: solid 2px @_color; 76 | } 77 | 78 | .article { 79 | .bordered(#ccc); 80 | color: #443d3d; 81 | } 82 | ``` 83 | 84 | Такая конструкция напоминает функции в JavaScript или других языках программирования, но на деле ей не является, так как работает скорее как макрос. 85 | 86 | ```css 87 | .article { 88 | border-top: dotted 1px #cccccc; 89 | border-bottom: solid 2px #cccccc; 90 | color: #443d3d; 91 | } 92 | ``` 93 | 94 | Параметров может быть неограниченное число, главное — чтобы они помещались на вашем экране и были читаемы. 95 | 96 | Разделять параметры при объявлении примеси и её вызове можно запятыми `(@a, @b)`, либо точкой с запятой `(@a; @b)`. 97 | 98 | 99 | #### Пример 3.4.1 100 | 101 | В этом примере отображена возможность работы с вложенными селекторами внутри примеси. 102 | 103 | ```less 104 | .clearfix() { 105 | &:before, 106 | &:after { 107 | display: table; 108 | content: ""; 109 | } 110 | 111 | &:after { 112 | clear: both; 113 | } 114 | } 115 | 116 | .navbar { 117 | .clearfix(); 118 | } 119 | ``` 120 | 121 | Ничего необычного, получен вполне ожидаемый результат: 122 | 123 | ```css 124 | .navbar:before, 125 | .navbar:after { 126 | display: table; 127 | content: ""; 128 | } 129 | .navbar:after { 130 | clear: both; 131 | } 132 | ``` 133 | 134 | Замечу ещё раз, что из-за указанных скобок у селектора `.clearfix`, соответствующий класс не будет объявлен после компиляции. 135 | 136 | 137 | 138 | 139 | ## Значения параметров по умолчанию 140 | 141 | Важной отличительной чертой примесей является возможность указывать значения по умолчанию для переменных. То есть в случае, если примесь вызвана, а значения для параметров не были переданы или переданы частично, то ошибки компилятор не выдаст, а возьмёт значение, указанное по умолчанию. 142 | 143 | ```less 144 | .bordered(@_color: #ccc) { 145 | border-top: dotted 1px @_color; 146 | border-bottom: solid 2px @_color; 147 | } 148 | 149 | .article { 150 | .bordered(); 151 | color: #443d3d; 152 | } 153 | ``` 154 | 155 | Эта запись не имела бы смысла, но так как указано значение по умолчанию, то при компиляции будет подставлено именно оно: 156 | 157 | ```css 158 | .article { 159 | border-top: dotted 1px #cccccc; 160 | border-bottom: solid 2px #cccccc; 161 | color: #443d3d; 162 | } 163 | ``` 164 | 165 | Все было бы хорошо, если бы для всех параметров указывались значения по умолчанию и их не нужно было изменять в зависимости от контекста применения примеси. На практике редко встречаются примеси, у которых используются указанные по умолчанию значения. 166 | 167 | Рассмотрим пару примеров, которые показывают различные ситуации, часто встречающиеся на практике в реальных проектах. 168 | 169 | 170 | #### Пример 3.4.2 171 | 172 | Иногда необходимо изменить не все параметры, а лишь некоторые из них. Делается это следующим образом: 173 | 174 | ```less 175 | .transition(@function: ease, @duration: .3s, @property: all) { 176 | transition-timing-function: @function; 177 | transition-duration: @duration; 178 | transition-property: @property; 179 | } 180 | 181 | .link { 182 | .transition(@duration: 1s); 183 | } 184 | ``` 185 | 186 | Вместо того, чтобы писать все три значения для переменных, я указал конкретную переменную и обновил её значение. Компилятор возьмёт значения по умолчанию для переменных `@function` и `@property`, а значение переменной `@duration` будет взято из объявления вызова примеси. 187 | 188 | ```css 189 | .link { 190 | transition-timing-function: ease; 191 | transition-duration: 1s; 192 | transition-property: all; 193 | } 194 | ``` 195 | 196 | 197 | #### Пример 3.4.3 198 | 199 | Если нужно изменить переменные, указанные слева, то писать переменные не нужно. Просто передайте при вызове необходимое количество значений. 200 | 201 | ```less 202 | .transition(@function: ease, @duration: .3s, @property: all) { 203 | transition-timing-function: @function; 204 | transition-duration: @duration; 205 | transition-property: @property; 206 | } 207 | 208 | .block { 209 | .transition(linear); 210 | } 211 | 212 | .link { 213 | .transition(linear, .5s); 214 | } 215 | ``` 216 | 217 | После компиляции получится следующая картина: 218 | 219 | ```css 220 | .block { 221 | transition-timing-function: linear; 222 | transition-duration: 0.3s; 223 | transition-property: all; 224 | } 225 | .link { 226 | transition-timing-function: linear; 227 | transition-duration: 0.5s; 228 | transition-property: all; 229 | } 230 | ``` 231 | 232 | 233 | #### Пример 3.4.4 234 | 235 | Внутри примеси можно творить все что угодно с переданными переменными и теми, что были указаны глобально. Этот пример я не могу продемонстрировать на реальном коде, так как стараюсь избегать взаимодействия глобальных и локальных переменных внутри примеси. 236 | 237 | ```less 238 | @global: 3; 239 | 240 | .calc(@a: 1, @b: 2, @c: @global) { 241 | @d: @a + @b + @c; 242 | content: @d; 243 | } 244 | 245 | .test { 246 | .calc(); 247 | } 248 | ``` 249 | 250 | Судя по правилам математики должно получиться 6. 251 | 252 | ```css 253 | .test { 254 | content: 6; 255 | } 256 | ``` 257 | 258 | 259 | 260 | 261 | ## Мысли и советы 262 | 263 | Используйте значения параметров по умолчанию, если это может сократить вызов примеси. Однако, при этом не должен потеряется смысл вызова, то есть разработчику должно быть понятно, что и как делает эта примесь. 264 | -------------------------------------------------------------------------------- /chapter_2/media-queries.md: -------------------------------------------------------------------------------- 1 | # Использование медиавыражений 2 | 3 | В 2015 году непозволительно иметь сайт, ориентирующийся только на пользователей стационарных ПК и ноутбуков. Благодаря доступности мобильных устройств и интернета, а также повсеместного внедрения Wi-Fi сетей, сайты всё больше получают «мобильных» посетителей. Я уже давно стал замечать, что использую ноутбук лишь для производства контента, а его потребление происходит, в основном, с помощью планшета и, изредка, смартфона. 4 | 5 | Для того, чтобы ориентировать сайт на все платформы нужно использовать медиавыражения, которые определяются с помощью директивы `@media`. 6 | 7 | 8 | 9 | 10 | ## Медиавыражения 11 | 12 | Пожалуй, перед тем, как бросаться на рассмотрение возможностей Less, которые помогут работать с медиавыражениями, я напомню, что они из себя представляют. 13 | 14 | **Медиавыражения** (от англ. media query) — это объявление директивы `@media` с одним или несколькими условиями, в зависимости от которых определяется будут ли срабатывать объявления внутри этой директивы или нет. 15 | 16 | В простейшем случае медиавыражение имеет такой вид: 17 | 18 | ```css 19 | @media (min-width: 992px) { 20 | .class { 21 | display: none; 22 | } 23 | } 24 | ``` 25 | 26 | Если при объявлении директивы используется несколько условий, то они объединяются с помощью ключевого слова `and`: 27 | 28 | ```css 29 | @media (min-width: 768px) and (orientation: landscape) { 30 | .class { 31 | display: none; 32 | } 33 | } 34 | 35 | @media tv and (min-width: 992px) and (orientation: landscape) { 36 | .class { 37 | display: block; 38 | } 39 | } 40 | ``` 41 | 42 | Такие конструкции позволяют применять те или иные свойства к элементам, в зависимости от выполнения некоторых условий. В основном, нас интересует: разрешение окна браузера, ориентация устройства и пиксельное соотношение (от англ. pixel ratio). Существуют и другие, но они применяются крайне редко. 43 | 44 | 45 | 46 | 47 | ## Медиавыражения в Less 48 | 49 | Препроцессор Less не привносит в синтаксис медиавыражений кардинальных изменений. Различие с CSS заключается в том, что здесь доступно два контекста использования и присутствует несколько особенностей. Рассматривать их отдельно и приводить примеры я не буду, а вот об особенностях поговорим подробнее, но позднее. 50 | 51 | **Стандартный контекст использования** такой же, как и в классическом CSS: 52 | 53 | ```less 54 | @media (min-width: 992px) { 55 | .class { 56 | display: none; 57 | // какие-то другие стили 58 | } 59 | } 60 | ``` 61 | 62 | **Стандартный для Less контекст использования**. Обратите внимание, медиавыражение вложено в селектор. А как уже известно, на этом и строится вся магия Less. 63 | 64 | ```less 65 | .class { 66 | .two { 67 | @media (min-width: 992px) { 68 | display: none; 69 | // какие-то другие стили 70 | } 71 | } 72 | } 73 | ``` 74 | 75 | После работы компилятора имеем следующий CSS-код: 76 | 77 | ```css 78 | @media (min-width: 992px) { 79 | .class .two { 80 | display: none; 81 | } 82 | } 83 | ``` 84 | 85 | Второй вариант использовать предпочтительнее, ввиду того, что он не требует слежения за правильностью структуры и вложенности. При этом нет необходимости исправлять названия селекторов, если они поменяются в процессе разработки, ведь компилятор сам уследит, к чему относится директива `@media`, а также объявленные внутри неё свойства и селекторы. 86 | 87 | Кроме положительных черт, у этого метода есть и отрицательные. Заключаются они в том, что разработчик практически не в состоянии повлиять на структуру вложенности. Единственный способ — это использование ссылки на родительский селектор. С другой стороны, желание повлиять на структуру медиавыражения возникает очень редко и на деле оно излишне, конечно, если не вдаваться в дебри оптимизации. 88 | 89 | 90 | 91 | 92 | ## Вложенные медиавыражения 93 | 94 | В самом начале главы вы узнали о том, что селекторы можно вкладывать друг в друга. Так вот, в этом случае медиавыражения схожи с селекторами. Вложенные конструкции будут склеиваться в одно медиавыражение с несколькими условиями. То есть, условия будут объединяться, а на каждом уровне вложенности будет собираться своё отдельное объявление директивы `@media`. 95 | 96 | 97 | #### Пример 2.5.1 98 | 99 | Рассмотрим пример того, как происходит компиляция вложенных медиавыражений. Напишем какое-нибудь непростое вложенное медиавыражение с вложенными селекторами: 100 | 101 | ```less 102 | .one { 103 | @media (min-width: 768px) { 104 | background-color: #f5f5f5; 105 | 106 | .two { 107 | @media (max-width: 992px) { 108 | color: #000; 109 | } 110 | } 111 | } 112 | } 113 | ``` 114 | 115 | Когда компилятор начнёт обрабатывать такую структуру, сначала будет создано медиавыражение с условием `(min-width: 768px)` и его свойствами, а уже потом со списком условий `(min-width: 768px) and (max-width: 992px)`. 116 | 117 | ```css 118 | @media (min-width: 768px) { 119 | .one { 120 | background-color: #f5f5f5; 121 | } 122 | } 123 | @media (min-width: 768px) and (max-width: 992px) { 124 | .one .two { 125 | color: #000; 126 | } 127 | } 128 | ``` 129 | 130 | **Предупреждение!** 131 | 132 | На практике такую возможность лучше не использовать. Да, это круто, когда есть способ слегка оптимизировать код в исходниках, но за счёт его читаемости. После компиляции всё равно будет два отдельных медиавыражения, то есть никакой выгоды в итоге вы не получите. Поэтому не стоит ухудшать читаемость кода за счёт сомнительной и бесполезной оптимизации. 133 | 134 | 135 | 136 | 137 | ## Медиавыражения и группировка селекторов 138 | 139 | Директива `@media` представляет собой замкнутую систему. Из школьного курса физики или химии известно, что замкнутая система — это такая система, которая не обменивается с окружающей средой ни веществом, ни энергией. В нашем случае энергией и веществом будут свойства и селекторы, объявленные внутри директивы. В идеальном случае, медиавыражения не могут воздействовать друг на друга. Получается, что группировать селекторы можно только внутри такой системы, не выходя за её пределы. Но, так как в реальности абсолютно замкнутых систем не бывает, воздействовать на неё извне мы сможем. 140 | 141 | 142 | #### Пример 2.5.2 143 | 144 | Давайте исходить от противного и экспериментально подтвердим факт того, что медиавыражения — это замкнутая система. Допустим, что у нас есть структура, в которой объявлены два вложенных медиавыражения, а также отдельно стоящий селектор. 145 | 146 | 147 | ```less 148 | @media screen { 149 | .one { 150 | &:extend(.three, .two); 151 | background-color: #fff; 152 | } 153 | 154 | @media (min-width: 992px) { 155 | .two { 156 | &:extend(.one); 157 | color: #777; 158 | } 159 | } 160 | } 161 | 162 | .three { 163 | border-right: 1px solid #000; 164 | } 165 | ``` 166 | 167 | Если выполнить компиляцию этого кода, то выполнится процедура объединения условий медиавыражения (пример 2.5.1), а вот группировки селекторов не произойдёт. Причём группировка не наблюдается ни в первом, ни во втором случае. Кроме того, изменения не коснутся и внешнего селектора. Отлично, значит утверждение о замкнутой системе верное. 168 | 169 | ```css 170 | @media screen { 171 | .one { 172 | background-color: #fff; 173 | } 174 | } 175 | @media screen and (min-width: 992px) { 176 | .two { 177 | color: #777; 178 | } 179 | } 180 | .three { 181 | border-right: 1px solid #000; 182 | } 183 | ``` 184 | 185 | 186 | #### Пример 2.5.3 187 | 188 | В этом примере будем рассматривать случай, когда мы можем воздействовать на замкнутую систему (медиавыражения). Для этого повторим поставленный в примере 2.5.2 эксперимент, но добавим группировку селекторов не в сами медиавыражения, а в отдельно стоящий селектор. 189 | 190 | ```less 191 | @media screen { 192 | .one { 193 | background-color: #fff; 194 | } 195 | 196 | @media (min-width: 992px) { 197 | .two { 198 | color: #777; 199 | } 200 | } 201 | } 202 | 203 | .test { 204 | &:extend(.one, .two); 205 | border-right: 1px solid #000; 206 | } 207 | ``` 208 | 209 | После работы компилятора на выходе имеем CSS-код, в котором группировка селекторов всё таки выполняется. Происходит это из-за того, что извне воздействовать на медиавыражения можно. 210 | 211 | ```css 212 | @media screen { 213 | .one, 214 | .test { 215 | background-color: #fff; 216 | } 217 | } 218 | @media screen and (min-width: 992px) { 219 | .two, 220 | .test { 221 | color: #777; 222 | } 223 | } 224 | .test { 225 | border-right: 1px solid #000; 226 | } 227 | ``` 228 | -------------------------------------------------------------------------------- /chapter_4/working-with-images.md: -------------------------------------------------------------------------------- 1 | # Работа с изображениями 2 | 3 | ## Размер изображения 4 | 5 | Отличительной особенностью Less версии 2.2.0 стали встроенные функции для работы с изображениями, которые позволяют получить следующие данные: 6 | 7 | * Размер (ширина и высота) — `image-size(url)`. 8 | * Ширину — `image-width(url)`. 9 | * Высоту — `image-height(url)`. 10 | 11 | Для того, чтобы получить ширину изображения, необходимо указать путь до него, относительно того файла, в котором вызывается эта функция. 12 | 13 | > **Замечание** 14 | > 15 | > Все примеры из этой части доступны в архиве, который прилагается к этой книге. 16 | 17 | Рассмотрим два случая, которые могут вводить новичков в заблуждение: 18 | 19 | 20 | 21 | ### Случай 1. Один файл 22 | 23 | Допустим, что работа ведётся с less-файлом, который находится в директории: 24 | 25 | ``` 26 | styles/less/_styles.less 27 | ``` 28 | 29 | В этом файле необходимо узнать ширину или высоту изображения, которое находится в директории: 30 | 31 | ``` 32 | images/logo.png 33 | ``` 34 | 35 | В этом случае, любая из трёх функций должна вызываться следующим образом: 36 | 37 | ```less 38 | @logo-path: "../../images/avatar.jpg"; 39 | 40 | .logo { 41 | @logo-width: image-width(@logo-path); 42 | @logo-height: image-height(@logo-path); 43 | @logo-size: image-size(@logo-path); 44 | 45 | content: "@{logo-size} [@{logo-width} x @{logo-height}]"; 46 | } 47 | ``` 48 | 49 | В итоге, если вы правильно укажете путь до файла изображения из файла, где была вызвана функция, свойство `content` получит значение: 50 | 51 | ```css 52 | .logo { 53 | content: "460px 460px [460px x 460px]"; 54 | } 55 | ``` 56 | 57 | Если же путь будет не верным, то компилятор выдаст ошибку. 58 | 59 | 60 | 61 | ### Случай 2. Структурный файл 62 | 63 | Ранее путь писался относительно того файла, в котором была вызвана та или иная функция для получения размера изображения. Допустим, что у нас имеется конфигурация: 64 | 65 | * Рабочий файл: `styles/less/components/_styles.less` 66 | * Главный файл: `styles/less/main.less` 67 | * Файл изображения: `images/logo.png` 68 | 69 | Содержимое каждого файла будет таким: 70 | 71 | ```less 72 | // file: `styles/less/main.less` 73 | 74 | @import "components/_styles.less"; 75 | 76 | // file: `styles/less/components/_styles.less` 77 | 78 | @logo-path: "../../images/avatar.jpg"; 79 | 80 | .logo { 81 | @logo-width: image-width(@logo-path); 82 | @logo-height: image-height(@logo-path); 83 | @logo-size: image-size(@logo-path); 84 | 85 | content: "@{logo-size} [@{logo-width} x @{logo-height}]"; 86 | } 87 | ``` 88 | 89 | Хотя файл `_styles.less` поменял своё расположение — при компиляции ошибки не будет. Дело в том, что путь, указанный в переменной `@logo-path` полностью соответствует ситуации. 90 | 91 | Вся хитрость заключается в файле `main.less`, который является точкой входа для компилятора. Именно относительно него нужно прописывать любой путь к изображениям. 92 | 93 | При попытке указать путь, относительно файла `_styles.less`, компилятор выдаст ошибку, говорящую о том, что по указанному пути файл не найден: 94 | 95 | ``` 96 | FileError: error evaluating function `image-width`: '../../../images/avatar.jpg' wasn't found. 97 | 98 | C:\<-- path -->\chapter_4\examples\4.3.2\styles\less\components\_styles.less on line 4, column 16: 99 | 3 .logo { 100 | 4 @logo-width: image-width(@logo-path); 101 | 5 @logo-height: image-height(@logo-path); 102 | ``` 103 | 104 | 105 | 106 | 107 | ## Встраиваемые ресурсы 108 | 109 | Под встроенными ресурсами стоит понимать закодированный ресурс (картинку, скрипт, стили), содержащийся внутри строки кода. 110 | 111 | Сейчас, в виду того, что дизайн веб-приложений становится плоским и материальным, а возможности браузеров растут (количество изображений в оформлении падает), довольно часто можно встреть следующую конструкцию в стилях: 112 | 113 | ```css 114 | .logo { 115 | /* Пример из документации */ 116 | background-image: url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg=='); 117 | } 118 | ``` 119 | Этот подход используется для того, чтобы уменьшить число HTTP-запросов к серверу и должен применяться только тогда, когда количество и размер изображений достаточно мал. 120 | 121 | При обнаружении такой конструкции в подключённых к странице стилях браузер декодирует строку, получает исходное изображение и выводит пользователю. 122 | 123 | В багажнике препроцессора Less есть мощная функция `data-uri()`, предоставляющая возможность кодировать ресурсы без использования сторонних инструментов. 124 | 125 | Синтаксис этой функции таков: 126 | 127 | ```less 128 | .logo { 129 | background-image: data-uri(mimetype, path); 130 | } 131 | ``` 132 | 133 | Параметр **mimetype** определяет строку, содержащую тип изображения для браузера в соответствии с принятым документом RFC 1521. Этот параметр необязателен и его можно опустить, так как компилятор сам в состоянии понять, какой ему ресурс предоставили для кодирования. 134 | 135 | Вот пример того, какие изображения можно закодировать с помощью этой функции и её результатов работы: 136 | 137 | ```less 138 | .logo { 139 | background-image: data-uri("image.jpg"); 140 | // url("data:image/jpeg;base64,/9j/7gAOQWRvYmUAZAAAAAAA/9sAQwA...") 141 | 142 | background-image: data-uri("image/jpeg;base64", "image.jpg"); 143 | // url("data:image/jpeg;base64,/9j/7gAOQWRvYmUAZAAAAAAA/9sAQwA...") 144 | 145 | background-image: data-uri("image.png"); 146 | // url("data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAB...") 147 | 148 | background-image: data-uri("image.gif"); 149 | // url("data:image/gif;base64,R0lGODlhQABAAPeAAP7+/v39/fz8/Pv7...") 150 | 151 | background-image: data-uri("image.svg"); 152 | // url("data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20e...") 153 | 154 | background-image: data-uri("image/svg+xml;charset=UTF-8", "image.svg"); 155 | // url("data:image/svg+xml;charset=UTF-8,%3C%3Fxml%20version%3...") 156 | } 157 | ``` 158 | 159 | Как не сложно заметить, различный результат проявился только у пары, где используется SVG изображение. 160 | 161 | 162 | 163 | 164 | ## SVG-градиенты 165 | 166 | Кроме стандартных функций для работы с изображениями и их кодированием, препроцессор Less умеет генерировать SVG-градиенты. Для этого используется функция, которая принимает на вход три параметра: *направление*, *цвет и позиция*. Вот синтаксис этой функции: 167 | 168 | ```less 169 | .gradient { 170 | background-image: svg-gradient(ellipse at center, blue, red 15%); 171 | } 172 | ``` 173 | 174 | Такой вызов функции породит Base64-код, в котором закодировано изображение сгенерированного градиента: 175 | 176 | ```css 177 | .gradient { 178 | background-image: url('data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%201%201%22%20preserveAspectRatio%3D%22none%22%3E%3CradialGradient%20id%3D%22gradient%22%20gradientUnits%3D%22userSpaceOnUse%22%20cx%3D%2250%25%22%20cy%3D%2250%25%22%20r%3D%2275%25%22%3E%3Cstop%20offset%3D%220%25%22%20stop-color%3D%22%230000ff%22%2F%3E%3Cstop%20offset%3D%2215%25%22%20stop-color%3D%22%23ff0000%22%2F%3E%3C%2FradialGradient%3E%3Crect%20x%3D%22-50%22%20y%3D%22-50%22%20width%3D%22101%22%20height%3D%22101%22%20fill%3D%22url(%23gradient)%22%20%2F%3E%3C%2Fsvg%3E'); 179 | } 180 | ``` 181 | 182 | При декодировании этого кода можно получить внутренности изображения и убедиться, что функция создала верный градиент: 183 | 184 | ```xml 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | ``` 196 | Конечно, функция может генерировать не только эллиптические градиенты. В список поддерживаемых направлений входят следующие значения: 197 | 198 | * to (top | right | bottom | left) 199 | * комбинации: to top bottom | to right bottom и прочие 200 | * ellipse 201 | * ellipse at center 202 | 203 | > **Внимание** 204 | > 205 | > Если вы используете компилятор версии ниже 2.2.0, то Base64 кодирование не поддерживается и, как следствие, функция `data-uri()` не будет работать. Кроме того, функция `svg-gradient()` не будет кодировать результат своей работы в Base64-код. 206 | -------------------------------------------------------------------------------- /chapter_1/css-reprocessors.md: -------------------------------------------------------------------------------- 1 | # CSS-препроцессоры 2 | 3 | Если рассматривать препроцессоры вместе с CSS, то получается картина более понятная, нежели чем рассматривать понятие препроцессора отдельно. 4 | 5 | 6 | 7 | 8 | ## Определение 9 | 10 | **CSS препроцессор** (от англ. CSS preprocessor) — это надстройка над CSS, которая добавляет ранее недоступные возможности для CSS, с помощью новых синтаксических конструкций. 11 | 12 | Основная задача препроцессора — это предоставление удобных синтаксических конструкций для разработчика, чтобы упростить, и тем самым, ускорить разработку и поддержу стилей в проектах. 13 | 14 | CSS препроцессоры преобразуют код, написанный с использованием препроцессорного языка, в чистый и валидный CSS-код. 15 | 16 | При помощи препроцессоров вы можете писать код, который нацелен на: 17 | 18 | * Читабельность для человека 19 | * Структурированность и логичность 20 | * Производительность 21 | 22 | И это лишь малая часть того, что может дать вам препроцессор. Но не стоит забегать вперёд. 23 | 24 | 25 | 26 | 27 | ## Синтаксический сахар 28 | 29 | Перед тем, как перейти к дальнейшему рассмотрению CSS-препроцессоров, давайте обновим наш лексикон новым понятием — «синтаксический сахар». 30 | 31 | **Синтаксический сахар** (от англ. syntactic sugar) — это дополнения синтаксиса языка программирования, которые не вносят каких-то существенных изменений или новых возможностей, но делают этот язык более читабельным для человека. 32 | 33 | Синтаксический сахар вводит в язык альтернативные варианты записи заложенных в этот язык конструкций. Под альтернативными вариантами записи стоит понимать более короткие или удобные конструкции для человека, которые в конечном итоге будут преобразовываться препроцессором в исходный язык, без синтаксического сахара. 34 | 35 | Если попытаться применить это понятие к CSS-препроцессорам, то оно, в общем случае, полностью описывает их суть. Ещё раз напомню, что основной задачей препроцессоров является упрощение и ускорение разработки, а как это ещё можно сделать, если не ввести альтернативные варианты записи? 36 | 37 | 38 | 39 | 40 | ## Какие бывают CSS-препроцессоры? 41 | 42 | Пора перейти к более конкретным примерам, а именно к самим CSS-препроцессорам. На момент написания книги можно выделить три популярных препроцессора: 43 | 44 | * Less 45 | * Sass (SCSS) 46 | * Stylus 47 | 48 | И несколько незначительных для нас игроков: 49 | 50 | * Closure Stylesheets 51 | * CSS Crush 52 | 53 | О первой тройке мы поговорим отдельно немногим ниже, а вот о двух последних разговора вообще не будет, в виду их непопулярности. При желании, описания этих препроцессоров с лёгкостью можно найти в поисковике. 54 | 55 | 56 | 57 | 58 | ## Какой смысл использования препроцессоров? 59 | 60 | Как я уже отметил выше, основные плюсы — это читабельность кода, структурирование и повышение производительности. 61 | 62 | Существуют также и другие причины того, чтобы начать использовать препроцессор уже сегодня. Я хочу заострить на этом внимание, так как разработчики раньше, да многие и сейчас, отнекиваются от использования препроцессоров, находя их сложными, непонятными и ненужными. 63 | 64 | 65 | #### CSS — это сложно 66 | 67 | Стандартный CSS — это сложно. Синтаксис без использования вложенности, которую предлагают CSS-препроцессоры, просто напросто сложен для зрительного восприятия. Кроме того, нужно помнить имя родителя при вложенности. Отсутствие нормальных переменных и «функций» делает CSS-код грязным и узконаправленным. 68 | 69 | 70 | #### Доступная документация 71 | 72 | Прошли те времена, когда документация от препроцессоров была доступна только людям «в теме». Сейчас любой желающий может в кратчайшие сроки освоить любой из препроцессоров, причём с минимальными затратами сил. 73 | 74 | 75 | #### Простота использования 76 | 77 | Использовать препроцессоры стало проще, чем раньше, причём намного проще. Для этого нужно лишь установить программу, которая будет следить за файлами, предназначенными для препроцессора, и при их изменении будет компилировать содержимое этих файлов в чистый CSS-код. 78 | 79 | Для более продвинутых пользователей есть специальные сборщики проектов. Не думайте, что если вы используете программу для препроцессоров, а не сборщик проектов, то вы недостаточно круты. На самом деле, такие сборщики предлагают полный контроль и расширенные настройки, а не делают из вас джедая. 80 | 81 | 82 | #### Структура и логичность кода 83 | 84 | Самым популярным предлагаемым функционалом любого CSS-препроцессора является возможность вкладывать селекторы друг в друга. Я не буду сейчас приводить пример, так как о возможностях Less, включая вложенность, будет написана соответствующая часть книги. На этом этапе вам стоит знать лишь то, что при использовании препроцессоров, можно вкладывать один селектор в другой, а другой в третий, получая что-то, похожее на оглавление книги: 85 | 86 | ``` 87 | 1. Родительский селектор 88 | 1.1. Вложенный селектор 89 | 1.2. Вложенный селектор 90 | 1.2.1. Вложенный селектор 91 | 1.3. Вложенный селектор 92 | ``` 93 | 94 | Конечно, в реальной жизни селекторы не могут начинаться с цифр, однако, для проведения параллели между вложенностью и оглавлением, думаю такое упущение здесь уместно. 95 | 96 | 97 | #### Примеси 98 | 99 | Если говорить совсем кратко, то, используя **примеси** (от англ. Mixins), можно сделать код переиспользуемым. Это помогает избежать вспомогательных классов в разметке или дублирования свойств от селектора к селектору. 100 | 101 | 102 | #### Модульность 103 | 104 | Еще одним бонусом, который прямо сейчас уговорил бы меня начать пользоваться CSS-препроцессором, будет возможность вкладывать файлы в файлы, то есть проще говоря, производить конкатенацию файлов в заданной последовательности. Да, это можно организовать и на чистом CSS, но вкупе с другими возможностями получается очень мощный инструмент. 105 | 106 | При этом мы получаем возможность делиться модулями (библиотеками примесей), которые создали для своих нужд и посчитали полезными для других людей. Получается, что любой разработчик может загрузить вашу библиотеку и использовать её в своих целях, вызывая по мере необходимости написанные вами примеси. 107 | 108 | 109 | 110 | 111 | ## Почему бы не подождать развития CSS? 112 | 113 | Развитие CSS идёт очень маленькими и неуверенными шагами, так как W3C придерживается приоритета скорости срабатывания CSS (производительности). С одной стороны это правильно и очень важно, но с другой — это отсутствие удобства для разработчиков. 114 | 115 | В пример поставлю одну из спецификаций CSS4, которую ввели под давлением разработчиков — селектор по родителю. Столь долгий путь от идеи до принятия решения был из-за того, что W3C считало такой селектор медленным и дальнейшее его использование на сайтах привело бы к диким тормозам. Конечно же, речь идёт о повсеместном применении этого селектора, а не о единичных случаях. 116 | 117 | Так что не стоит ждать в ближайшее время революций и изменений, способных затмить функционал и возможности CSS-препроцессоров. 118 | 119 | 120 | 121 | 122 | ## Разновидности препроцессоров 123 | 124 | Разумеется, как и в любой другой области, всегда есть конкуренция, и на рынке препроцессоров сейчас три главных, враждующих между собой лагеря: 125 | 126 | * Less 127 | * Sass (SCSS) 128 | * Stylus 129 | 130 | Враждующими я их называю, потому что каждый приверженец одного из препроцессоров считает своим долгом поливать нечистотами представителей других, скажем так, конфессий. Такая неприязнь особенно часто проявляется у любителей препроцессора Sass, который считается старейшим и мощнейшим из всех трёх препроцессоров. 131 | 132 | Для полной картины, я хочу привести краткую справку по каждому препроцессору: 133 | 134 | 135 | #### Less 136 | 137 | Собственно, герой этой книги. Самый популярный на момент написания книги препроцессор. Основан в 2009 году Алексис Сельер (Alexis Sellier) и написан на JavaScript (изначально был написан на Ruby, но Алексис вовремя сделал правильный шаг). Имеет все базовые возможности препроцессоров и даже больше, но не имеет условных конструкций и циклов в привычном для нас понимании. Основным плюсом является его простота, практически стандартный для CSS синтаксис и возможность расширения функционала за счёт системы плагинов. 138 | 139 | 140 | #### Sass (SCSS) 141 | 142 | Самый мощный из CSS-препроцессоров. Имеет довольно большое сообщество разработчиков. Основан в 2007 году как модуль для HAML и написан на Ruby (есть порт на C++). Имеет куда больший ассортимент возможностей в сравнении с Less. Возможности самого препроцессора расширяются за счёт многофункциональной библиотеки Compass, которая позволяет выйти за рамки CSS и работать, например, со спрайтами в автоматическом режиме. 143 | 144 | Имеет два синтаксиса: 145 | 146 | * Sass (Syntactically Awesome Style Sheets) — упрощённый синтаксис CSS, 147 | который основан на идентации. Считается устаревшим. 148 | * SCSS (Sassy CSS) — основан на стандартном для CSS синтаксисе. 149 | 150 | 151 | #### Stylus 152 | 153 | Самый молодой, но в тоже время самый перспективный CSS-препроцессор. Основан в 2010 году небезызвестной в наших кругах личностью TJ Holowaychuk. Говорят, это самый удобный и расширяемый препроцессор, а ещё он гибче Sass. Написан на JavaScript. Поддерживает уйму вариантов синтаксиса от подобного CSS до упрощённого (отсутствуют `:`, `;`, `{}` и некоторые скобки). 154 | -------------------------------------------------------------------------------- /examples/chapter_2/homework/less/_normalize.less: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | // 4 | // 1. Set default font family to sans-serif. 5 | // 2. Prevent iOS text size adjust after orientation change, without disabling 6 | // user zoom. 7 | // 8 | 9 | html { 10 | font-family: sans-serif; // 1 11 | -ms-text-size-adjust: 100%; // 2 12 | -webkit-text-size-adjust: 100%; // 2 13 | } 14 | 15 | // 16 | // Remove default margin. 17 | // 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | // HTML5 display definitions 24 | // ========================================================================== 25 | 26 | // 27 | // Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | // Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | // and Firefox. 30 | // Correct `block` display not defined for `main` in IE 11. 31 | // 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | // 50 | // 1. Correct `inline-block` display not defined in IE 8/9. 51 | // 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | // 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; // 1 59 | vertical-align: baseline; // 2 60 | } 61 | 62 | // 63 | // Prevent modern browsers from displaying `audio` without controls. 64 | // Remove excess height in iOS 5 devices. 65 | // 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | // 73 | // Address `[hidden]` styling not present in IE 8/9/10. 74 | // Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | // 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | // Links 83 | // ========================================================================== 84 | 85 | // 86 | // Remove the gray background color from active links in IE 10. 87 | // 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | // 94 | // Improve readability when focused and also mouse hovered in all browsers. 95 | // 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | // Text-level semantics 103 | // ========================================================================== 104 | 105 | // 106 | // Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | // 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | // 114 | // Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | // 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | // 123 | // Address styling not present in Safari and Chrome. 124 | // 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | // 131 | // Address variable `h1` font-size and margin within `section` and `article` 132 | // contexts in Firefox 4+, Safari, and Chrome. 133 | // 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | // 141 | // Address styling not present in IE 8/9. 142 | // 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | // 150 | // Address inconsistent and variable font size in all browsers. 151 | // 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | // 158 | // Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | // 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | // Embedded content 178 | // ========================================================================== 179 | 180 | // 181 | // Remove border when inside `a` element in IE 8/9/10. 182 | // 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | // 189 | // Correct overflow not hidden in IE 9/10/11. 190 | // 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | // Grouping content 197 | // ========================================================================== 198 | 199 | // 200 | // Address margin not present in IE 8/9 and Safari. 201 | // 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | // 208 | // Address differences between Firefox and other browsers. 209 | // 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | // 218 | // Contain overflow in all browsers. 219 | // 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | // 226 | // Address odd `em`-unit font size rendering in all browsers. 227 | // 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | // Forms 238 | // ========================================================================== 239 | 240 | // 241 | // Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | // styling of `select`, unless a `border` property is set. 243 | // 244 | 245 | // 246 | // 1. Correct color not being inherited. 247 | // Known issue: affects color of disabled elements. 248 | // 2. Correct font properties not being inherited. 249 | // 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | // 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; // 1 258 | font: inherit; // 2 259 | margin: 0; // 3 260 | } 261 | 262 | // 263 | // Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | // 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | // 271 | // Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | // All other form control elements do not inherit `text-transform` values. 273 | // Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | // Correct `select` style inheritance in Firefox. 275 | // 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | // 283 | // 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | // and `video` controls. 285 | // 2. Correct inability to style clickable `input` types in iOS. 286 | // 3. Improve usability and consistency of cursor style between image-type 287 | // `input` and others. 288 | // 289 | 290 | button, 291 | html input[type="button"], // 1 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; // 2 295 | cursor: pointer; // 3 296 | } 297 | 298 | // 299 | // Re-set default cursor for disabled elements. 300 | // 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | // 308 | // Remove inner padding and border in Firefox 4+. 309 | // 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | // 318 | // Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | // the UA stylesheet. 320 | // 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | // 327 | // It's recommended that you don't attempt to style these elements. 328 | // Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | // 330 | // 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | // 2. Remove excess padding in IE 8/9/10. 332 | // 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; // 1 337 | padding: 0; // 2 338 | } 339 | 340 | // 341 | // Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | // `font-size` values of the `input`, it causes the cursor style of the 343 | // decrement button to change from `default` to `text`. 344 | // 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | // 352 | // 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | // 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | // (include `-moz` to future-proof). 355 | // 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; // 1 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; // 2 361 | box-sizing: content-box; 362 | } 363 | 364 | // 365 | // Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | // Safari (but not Chrome) clips the cancel button when the search input has 367 | // padding (and `textfield` appearance). 368 | // 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | // 376 | // Define consistent border, margin, and padding. 377 | // 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | // 386 | // 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | // 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | // 389 | 390 | legend { 391 | border: 0; // 1 392 | padding: 0; // 2 393 | } 394 | 395 | // 396 | // Remove default vertical scrollbar in IE 8/9/10/11. 397 | // 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | // 404 | // Don't inherit the `font-weight` (applied by a rule above). 405 | // NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | // 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | // Tables 413 | // ========================================================================== 414 | 415 | // 416 | // Remove most spacing between table cells. 417 | // 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } -------------------------------------------------------------------------------- /examples/chapter_3/homework/less/_normalize.less: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | // 4 | // 1. Set default font family to sans-serif. 5 | // 2. Prevent iOS text size adjust after orientation change, without disabling 6 | // user zoom. 7 | // 8 | 9 | html { 10 | font-family: sans-serif; // 1 11 | -ms-text-size-adjust: 100%; // 2 12 | -webkit-text-size-adjust: 100%; // 2 13 | } 14 | 15 | // 16 | // Remove default margin. 17 | // 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | // HTML5 display definitions 24 | // ========================================================================== 25 | 26 | // 27 | // Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | // Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | // and Firefox. 30 | // Correct `block` display not defined for `main` in IE 11. 31 | // 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | // 50 | // 1. Correct `inline-block` display not defined in IE 8/9. 51 | // 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | // 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; // 1 59 | vertical-align: baseline; // 2 60 | } 61 | 62 | // 63 | // Prevent modern browsers from displaying `audio` without controls. 64 | // Remove excess height in iOS 5 devices. 65 | // 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | // 73 | // Address `[hidden]` styling not present in IE 8/9/10. 74 | // Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | // 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | // Links 83 | // ========================================================================== 84 | 85 | // 86 | // Remove the gray background color from active links in IE 10. 87 | // 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | // 94 | // Improve readability when focused and also mouse hovered in all browsers. 95 | // 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | // Text-level semantics 103 | // ========================================================================== 104 | 105 | // 106 | // Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | // 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | // 114 | // Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | // 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | // 123 | // Address styling not present in Safari and Chrome. 124 | // 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | // 131 | // Address variable `h1` font-size and margin within `section` and `article` 132 | // contexts in Firefox 4+, Safari, and Chrome. 133 | // 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | // 141 | // Address styling not present in IE 8/9. 142 | // 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | // 150 | // Address inconsistent and variable font size in all browsers. 151 | // 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | // 158 | // Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | // 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | // Embedded content 178 | // ========================================================================== 179 | 180 | // 181 | // Remove border when inside `a` element in IE 8/9/10. 182 | // 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | // 189 | // Correct overflow not hidden in IE 9/10/11. 190 | // 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | // Grouping content 197 | // ========================================================================== 198 | 199 | // 200 | // Address margin not present in IE 8/9 and Safari. 201 | // 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | // 208 | // Address differences between Firefox and other browsers. 209 | // 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | // 218 | // Contain overflow in all browsers. 219 | // 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | // 226 | // Address odd `em`-unit font size rendering in all browsers. 227 | // 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | // Forms 238 | // ========================================================================== 239 | 240 | // 241 | // Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | // styling of `select`, unless a `border` property is set. 243 | // 244 | 245 | // 246 | // 1. Correct color not being inherited. 247 | // Known issue: affects color of disabled elements. 248 | // 2. Correct font properties not being inherited. 249 | // 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | // 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; // 1 258 | font: inherit; // 2 259 | margin: 0; // 3 260 | } 261 | 262 | // 263 | // Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | // 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | // 271 | // Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | // All other form control elements do not inherit `text-transform` values. 273 | // Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | // Correct `select` style inheritance in Firefox. 275 | // 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | // 283 | // 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | // and `video` controls. 285 | // 2. Correct inability to style clickable `input` types in iOS. 286 | // 3. Improve usability and consistency of cursor style between image-type 287 | // `input` and others. 288 | // 289 | 290 | button, 291 | html input[type="button"], // 1 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; // 2 295 | cursor: pointer; // 3 296 | } 297 | 298 | // 299 | // Re-set default cursor for disabled elements. 300 | // 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | // 308 | // Remove inner padding and border in Firefox 4+. 309 | // 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | // 318 | // Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | // the UA stylesheet. 320 | // 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | // 327 | // It's recommended that you don't attempt to style these elements. 328 | // Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | // 330 | // 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | // 2. Remove excess padding in IE 8/9/10. 332 | // 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; // 1 337 | padding: 0; // 2 338 | } 339 | 340 | // 341 | // Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | // `font-size` values of the `input`, it causes the cursor style of the 343 | // decrement button to change from `default` to `text`. 344 | // 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | // 352 | // 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | // 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | // (include `-moz` to future-proof). 355 | // 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; // 1 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; // 2 361 | box-sizing: content-box; 362 | } 363 | 364 | // 365 | // Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | // Safari (but not Chrome) clips the cancel button when the search input has 367 | // padding (and `textfield` appearance). 368 | // 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | // 376 | // Define consistent border, margin, and padding. 377 | // 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | // 386 | // 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | // 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | // 389 | 390 | legend { 391 | border: 0; // 1 392 | padding: 0; // 2 393 | } 394 | 395 | // 396 | // Remove default vertical scrollbar in IE 8/9/10/11. 397 | // 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | // 404 | // Don't inherit the `font-weight` (applied by a rule above). 405 | // NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | // 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | // Tables 413 | // ========================================================================== 414 | 415 | // 416 | // Remove most spacing between table cells. 417 | // 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } --------------------------------------------------------------------------------