├── .github
└── workflows
│ └── publish.yml
├── .gitignore
├── README.md
├── docs
└── en.md
├── gulpfile.js
├── package-lock.json
├── package.json
└── src
├── blocks
├── footer.html
├── head.html
├── nav.html
└── scripts.html
├── checklist.html
├── css
├── _constants.css
├── adornment.css
├── checklist.css
├── footer.css
├── globals.css
├── grid.css
├── header.css
├── nav.css
├── section.css
├── style.css
├── themes
│ ├── _breakpoints.css
│ ├── _dark.css
│ └── _light.css
└── toggle.css
├── index.html
├── js
├── nav.js
└── theme-toggle.js
├── sections
├── afterwords.html
├── backender.html
├── conversation.html
├── conveyor.html
├── deisgner.html
├── editor.html
├── engineer.html
├── header.html
├── kiss.html
├── knowledge-and-questions.html
├── manager.html
├── pain.html
├── preface.html
├── problem.html
├── product.html
├── products-evolve.html
├── progress.html
├── tester.html
└── you-know-your-shit.html
└── static
├── humans.txt
├── img
├── crescent.svg
├── resize
│ ├── djenga.jpg
│ ├── do-it-ok.jpg
│ ├── do-it-right.jpg
│ ├── garold-1.jpg
│ ├── have-done.jpg
│ ├── image-harolds.jpg
│ ├── sceptic.jpg
│ ├── table-flip.jpg
│ ├── tools.jpg
│ ├── waaait.jpg
│ ├── wait-but.jpg
│ ├── wait-but.png
│ └── yoda.jpg
├── sad-frontender.jpg
├── sun.svg
├── typical-designer.jpg
└── typical-designer@2x.jpg
├── meta
├── favicon-180.png
├── favicon-192.png
├── favicon-512.png
├── favicon.ico
├── favicon.svg
└── site.webmanifest
└── robots.txt
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | paths:
8 | - "src/**"
9 |
10 | jobs:
11 | publish:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 | - uses: actions/setup-node@v4
17 | with:
18 | node-version: "20"
19 |
20 | - run: sudo apt-get install imagemagick
21 | - run: sudo apt-get install graphicsmagick
22 | - run: npm ci
23 | - run: npm run build
24 |
25 | - name: Deploy
26 | uses: SamKirkland/FTP-Deploy-Action@4.3.3
27 | with:
28 | server: ${{ secrets.DEPLOY_HOST }}
29 | username: ${{ secrets.DEPLOY_USERNAME }}
30 | password: ${{ secrets.DEPLOY_PASSWORD }}
31 | local-dir: "build/"
32 | log-level: minimal
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | build
3 | *.log
4 |
5 | src/static/img/tmp/*
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > [Read description in English](./docs/en.md). The project translation is on the way. Stay tuned!
2 |
3 | # Фронтенд — это не больно!
4 |
5 | О том как работать в кайф. [Пособие](https://bespoyasov.ru/front-not-pain/) для разработчиков и сочувствующих.
6 |
7 | ## О чём это и для кого
8 |
9 | У фронтендеров часто бомбит.
10 |
11 | Дизайнеры просят подвинуть логотип на пиксель вправо, 100500 раз переделывают уже готовые страницы, бекендеры ломают API, тестировщики кидают таски обратно в разработку, менеджеры ставят адовые сроки.
12 |
13 | Грустные фронтендеры пытаются бороться с этим, но сдаются и утопают в рутине.
14 |
15 | 
16 |
17 | Это пособие поможет им справляться с задачами быстрее и качественнее, научиться разделываться с рутиной и получать удовольствие от работы.
18 |
19 | Читайте, делитесь, предлагайте идеи и улучшения! Сделаем нашу работу проще :–)
20 |
21 | ## Ссылочки
22 |
23 | - [Пособие «Фронтенд — это не больно!»](https://bespoyasov.ru/front-not-pain/)
24 | - [Чеклист: что делать, чему учиться, как себя проверять](https://bespoyasov.ru/front-not-pain/checklist.html)
25 |
26 | ## Лицензии
27 |
28 | Текст пособия распространяется под лицензией [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). Вы можете копировать, изменять и использовать его в проектах на некоммерческой основе. Исходный код проекта распространяется под лицензией [MIT](https://opensource.org/licenses/MIT).
29 |
--------------------------------------------------------------------------------
/docs/en.md:
--------------------------------------------------------------------------------
1 | # Frontend without Pain!
2 |
3 | [Handbook](https://bespoyasov.ru/front-not-pain/) for developers and those who care.
4 |
5 | > Read [in Russian](../README.md).
6 |
7 | ## About Project
8 |
9 | Frontend development can be difficult.
10 |
11 | Designers ask to move the logo one pixel left-right, 100500 times they redo the page designs, backend developers break the API, testers throw the task back into development, managers set hell of a deadline.
12 |
13 | Sad frontend developers try to fight it, but give up and drown in the routine. This handbook will help them handle tasks faster and better, learn how to cut through the routine and enjoy the work.
14 |
15 | Read it, share, and suggest ideas and improvements! Let's make our job easier :–)
16 |
17 | ## Project Sources
18 |
19 | - [Tutorial “Frontend without Pain!”](https://bespoyasov.ru/front-not-pain/)
20 | - [Checklist: what to do, what to learn, how to check yourself](https://bespoyasov.ru/front-not-pain/checklist.html)
21 |
22 | P.S. The book is written in Russian. If you want to help with translation, ping us in issues or by email!
23 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import gulp from "gulp";
3 |
4 | import rename from "gulp-rename";
5 | import clean from "gulp-clean";
6 | import concat from "gulp-concat";
7 | import minify from "gulp-minify";
8 |
9 | import include from "gulp-include";
10 | import typograf from "gulp-typograf";
11 | import htmlmin from "gulp-htmlmin";
12 | import importCss from "gulp-import-css";
13 |
14 | import imagemin from "gulp-imagemin";
15 | import imageResize from "gulp-image-resize";
16 | import webp from "gulp-webp";
17 | import avif from "gulp-avif";
18 |
19 | import webserver from "gulp-webserver";
20 |
21 | function html() {
22 | const nonBreakingHyphen = "‑";
23 | const typografRules = [
24 | {
25 | name: "common/other/nonBreakingHyphen",
26 | handler: (text) => text.replace(/\-/g, nonBreakingHyphen),
27 | },
28 | {
29 | name: "common/other/typographicalEmoticon",
30 | handler: (text) =>
31 | text
32 | .replace(/\:\ \–\)/g, ":–)")
33 | .replace(/\:\ \–\(/g, ":–(")
34 | .replace(/\;\ \–\)/g, ";–)"),
35 | },
36 | ];
37 |
38 | return gulp
39 | .src("./src/*.html")
40 | .pipe(include())
41 | .on("error", console.log)
42 | .pipe(
43 | typograf({
44 | locale: ["ru", "en-US"],
45 | enableRule: ["ru/optalign/*"],
46 | disableRule: ["ru/nbsp/afterNumberSign"],
47 | rules: typografRules,
48 | })
49 | )
50 | .pipe(htmlmin({ collapseWhitespace: true }))
51 | .pipe(gulp.dest("./build/"));
52 | }
53 |
54 | function css() {
55 | return gulp
56 | .src("./src/css/style.css")
57 | .pipe(importCss())
58 | .pipe(gulp.dest("./build/css/"));
59 | }
60 |
61 | function js() {
62 | const internal = ["./src/js/**/*.js"];
63 | const external = ["node_modules/ilyabirman-likely/release/likely.min.js"];
64 |
65 | return gulp
66 | .src([...internal, ...external])
67 | .pipe(concat("scripts.js"))
68 | .pipe(minify())
69 | .pipe(gulp.dest("./build/js/"));
70 | }
71 |
72 | function resize(done) {
73 | const source = "./src/static/img/resize/**/*.{jpg,png}";
74 | const target = "./src/static/img/tmp/";
75 |
76 | const x1 = () =>
77 | gulp
78 | .src(source)
79 | .pipe(imageResize({ width: 320 }))
80 | .pipe(gulp.dest(target));
81 |
82 | const x2 = () =>
83 | gulp
84 | .src(source)
85 | .pipe(imageResize({ width: 640 }))
86 | .pipe(rename((path) => (path.basename += "@2x")))
87 | .pipe(gulp.dest(target));
88 |
89 | return gulp.parallel(x1, x2)(done);
90 | }
91 |
92 | function images(done) {
93 | const minifiable = [
94 | "./src/static/img/*.{jpg,png,svg}",
95 | "./src/static/img/tmp/*.{jpg,png}",
96 | ];
97 |
98 | const convertible = [
99 | "./src/static/img/*.{jpg,png}",
100 | "./src/static/img/tmp/*.{jpg,png}",
101 | ];
102 |
103 | const target = "./build/img/";
104 |
105 | const minify = () =>
106 | gulp.src(minifiable).pipe(imagemin()).pipe(gulp.dest(target));
107 |
108 | const toWebp = () =>
109 | gulp.src(convertible).pipe(webp()).pipe(gulp.dest(target));
110 |
111 | const toAvif = () =>
112 | gulp.src(convertible).pipe(avif()).pipe(gulp.dest(target));
113 |
114 | return gulp.series(resize, gulp.parallel(minify, toWebp, toAvif))(done);
115 | }
116 |
117 | function meta(done) {
118 | const txt = () => gulp.src("./src/static/*.txt").pipe(gulp.dest("./build/"));
119 | const icons = () =>
120 | gulp.src("./src/static/meta/*").pipe(gulp.dest("./build/meta/"));
121 |
122 | return gulp.parallel(icons, txt)(done);
123 | }
124 |
125 | function cleanup() {
126 | return gulp
127 | .src("./src/static/img/tmp", { read: false, allowEmpty: true })
128 | .pipe(clean());
129 | }
130 |
131 | function server() {
132 | return gulp.src("./build/").pipe(
133 | webserver({
134 | livereload: { enable: true },
135 | open: "http://localhost:8001/",
136 | port: 8001,
137 | })
138 | );
139 | }
140 |
141 | gulp.task("watch", function () {
142 | gulp.watch("./src/**/*.html", html);
143 | gulp.watch("./src/css/*.css", css);
144 | gulp.watch("./src/js/**/*.js", js);
145 | });
146 |
147 | gulp.task("default", gulp.series(html, css, js, images, server, "watch"));
148 | gulp.task("build", gulp.series(html, css, js, images, meta, cleanup));
149 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "front-not-pain",
3 | "version": "2.0.0",
4 | "description": "О том как работать без напряга. Пособие для фронтенд-разработчиков и сочувствующих",
5 | "type": "module",
6 | "scripts": {
7 | "start": "gulp",
8 | "build": "gulp build"
9 | },
10 | "author": "Alexander Bespoyasov",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "gulp": "^4.0.2",
14 | "gulp-avif": "^1.1.0",
15 | "gulp-clean": "^0.4.0",
16 | "gulp-concat": "^2.6.1",
17 | "gulp-cssmin": "^0.2.0",
18 | "gulp-htmlmin": "^5.0.1",
19 | "gulp-image-resize": "^0.13.0",
20 | "gulp-imagemin": "^9.0.0",
21 | "gulp-import-css": "^0.1.3",
22 | "gulp-include": "^2.3.1",
23 | "gulp-minify": "^3.1.0",
24 | "gulp-rename": "^2.0.0",
25 | "gulp-typograf": "^4.0.3",
26 | "gulp-webp": "^5.0.0",
27 | "gulp-webserver": "^0.9.1"
28 | },
29 | "dependencies": {
30 | "ilyabirman-likely": "^3.0.0"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/blocks/footer.html:
--------------------------------------------------------------------------------
1 |
31 |
--------------------------------------------------------------------------------
/src/blocks/head.html:
--------------------------------------------------------------------------------
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 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/blocks/nav.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/blocks/scripts.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/checklist.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Чеклист
9 |
Что делать, чему учиться, как себя проверять.
10 |
11 |
12 |
13 |
14 |
Переговоры
15 |
16 | Обсуждать с дизайнером непонятные места в макетах
17 | Обсуждать с бекендером API
18 | Не воспринимать критику, как оскорбление, прислушиваться к замечаниям
19 | Обсуждать слабые или непонятные решения
20 | Запоминать объяснения членов команды
21 | Вести чеклисты
22 |
23 |
24 |
Дизайн
25 |
26 | Дизайнить простые страницы самостоятельно
27 | Использовать инструменты для создания анимаций
28 | Придумывать дизайн-решения и утверждать их у дизайнера
29 | Править интерфейсные ошибки в своих проектах
30 |
31 |
32 |
33 |
34 |
Текст и редактура
35 |
36 | Писать рассказы о проектах для резюме или портфолио
37 | Проверять подписи полей и заголовки перед выпуском в продакшен
38 |
39 |
40 |
Бекенд и программирование
41 |
42 | Пробовать писать серверные приложения
43 | Учиться работать с базами данных
44 | Улучшать интерфейсы своих функций и методов
45 | Пользоваться гитом
46 | Осваивать шаблоны проектирования
47 | Разбивать проект на заменяемые модули и компоненты
48 | Рефакторить плохой код
49 | Документировать свой код
50 |
51 |
52 |
Тестирование
53 |
54 | Писать тесты
55 | Автоматизировать запуск тестов
56 |
57 |
58 |
59 |
60 |
Решение задач
61 |
62 | Не начинать задачу без понимания
63 | Продумывать решение комплексно, расписывать задачи на бумаге
64 | Думать над расширяемостью и возможными проблемами
65 |
66 |
67 |
Управление временем и ответственность
68 |
69 | Учиться «сделывать»
70 | Ставить сроки и укладываться в них
71 | Не терять фокус во время работы
72 |
73 |
74 |
Развитие и мотивация
75 |
76 | Изучать другие языки
77 | Осваивать смежные области знаний
78 | Разбираться с мотивацией, искать то, что приносит в работе удовольствие
79 | Делиться кайфовыми вещами с сообществом
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/css/_constants.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --font-serif: "PT Serif";
3 | --font-sans-serif: "PT Sans", sans-serif;
4 |
5 | --nav-width: 200px;
6 | --right-column-width: 28%;
7 | --right-column-max-width: 240px;
8 | --right-column-padding: 60px;
9 |
10 | --header-background: #526850;
11 | --toggle-background: rgba(156, 174, 192, 0.27);
12 | --toggle-border: #333333;
13 |
14 | --background-color: var(--white);
15 | --text-color: var(--black);
16 | --link-color: var(--blue);
17 | --link-border-color: var(--blue-transparent);
18 | --link-border-color-visited: var(--purple-transparent);
19 | --link-border-color-hover: var(--red-transparent);
20 | --link-color-visited: var(--purple);
21 | --active-nav: var(--red);
22 | --figcaption: var(--grey-5);
23 | --blockquote-background: var(--light-brown);
24 | --blockquote-before-background: var(--grey-1);
25 | --mark-color: var(--black);
26 | --footer-links-color: var(--grey-5);
27 | --footer-links-color-hover: var(--black);
28 | --footer-links-border-color: var(--grey-2);
29 | --footer-links-border-color-hover: var(--grey-3);
30 | --table-border-color: var(--grey-05);
31 | }
32 |
33 | @media (max-width: 1060px) {
34 | :root {
35 | --nav-width: 160px;
36 | --right-column-width: 25%;
37 | --right-column-max-width: 220px;
38 | --right-column-padding: 40px;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/css/adornment.css:
--------------------------------------------------------------------------------
1 | .adorned::after {
2 | margin-left: 0.4em;
3 | }
4 |
5 | .adorned--books::after {
6 | content: "📖";
7 | }
8 |
9 | .adorned--posts::after {
10 | content: "📝";
11 | }
12 |
13 | .adorned--video::after {
14 | content: "📹";
15 | }
16 |
17 | .adorned--tools::after {
18 | content: "🔨";
19 | }
20 |
21 | .adorned--steps::after {
22 | content: "⚡️";
23 | }
24 |
--------------------------------------------------------------------------------
/src/css/checklist.css:
--------------------------------------------------------------------------------
1 | .checklist {
2 | max-width: 1100px;
3 | margin: auto;
4 | padding: 50px 0;
5 | }
6 |
7 | .checklist .grid {
8 | padding-top: 40px;
9 | }
10 |
11 | .checklist .column {
12 | padding: 0 25px;
13 | width: 33%;
14 | margin: 0;
15 | }
16 |
17 | .checklist .column:first-child {
18 | padding-left: 0;
19 | }
20 | .checklist .column:last-child {
21 | padding-right: 0;
22 | }
23 |
24 | .checklist .caption {
25 | font-size: 1rem;
26 | }
27 |
28 | .checklist .tutorials {
29 | margin: 0;
30 | list-style: disc;
31 | font-size: 1rem;
32 | }
33 |
34 | .checklist .tutorials li {
35 | list-style: disc;
36 | position: relative;
37 | margin-left: 20px;
38 | }
39 |
40 | .checklist input {
41 | position: absolute;
42 | left: 0;
43 | top: 6px;
44 | }
45 |
46 | @media (max-width: 800px) {
47 | .checklist .column {
48 | width: 100%;
49 | margin: 0;
50 | padding: 0 0 1.5rem;
51 | }
52 | .checklist .caption {
53 | margin-left: 0;
54 | }
55 | .checklist input {
56 | top: 3px;
57 | }
58 | .checklist .grid {
59 | padding-top: 25px;
60 | }
61 | }
62 |
63 | @media print {
64 | .checklist {
65 | padding: 30px 0;
66 | }
67 |
68 | .checklist h1 {
69 | font-size: 40px;
70 | line-height: 0.8em;
71 | margin-bottom: 10px;
72 | padding-bottom: 0;
73 | }
74 |
75 | .checklist p {
76 | font-size: 15px;
77 | }
78 |
79 | .checklist .tutorials,
80 | .checklist .tutorials li,
81 | .checklist .caption {
82 | font-size: 15px;
83 | }
84 |
85 | .checklist .grid {
86 | padding-top: 30px;
87 | }
88 |
89 | .checklist .column {
90 | padding: 0 15px;
91 | }
92 | .checklist .column:first-child {
93 | padding-left: 0;
94 | }
95 | .checklist .column:last-child {
96 | padding-right: 0;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/css/footer.css:
--------------------------------------------------------------------------------
1 | .footer-socials {
2 | text-align: center;
3 | margin: auto;
4 | display: block;
5 | padding: 20px 0 15px;
6 | }
7 |
8 | .footer-links {
9 | font-size: 0.7rem;
10 | padding: 0 0 25px 0;
11 | font-family: var(--font-sans-serif);
12 | }
13 |
14 | .footer-links ul {
15 | display: flex;
16 | list-style: none;
17 | justify-content: center;
18 | flex-wrap: wrap;
19 | }
20 |
21 | .footer-links li {
22 | list-style: none;
23 | padding: 0 0.5rem;
24 | }
25 |
26 | .footer-links a {
27 | color: var(--footer-links-color);
28 | border-color: var(--footer-links-border-color);
29 | }
30 |
31 | .footer-links a:hover {
32 | color: var(--footer-links-color-hover);
33 | border-color: var(--footer-links-border-color-hover);
34 | }
35 |
36 | .footer .grid {
37 | justify-content: space-between;
38 | }
39 |
40 | .footer .column {
41 | width: auto;
42 | flex: auto;
43 | }
44 |
45 | .footer .likely .likely__counter {
46 | display: none;
47 | }
48 | .footer .likely .likely__button {
49 | font-size: 0.7rem;
50 | }
51 |
52 | @media (max-width: 980px) {
53 | .footer .likely .likely__button,
54 | .footer-links {
55 | font-size: 0.8rem;
56 | }
57 | }
58 |
59 | @media (max-width: 800px) {
60 | .footer-links ul {
61 | line-height: 1.6em;
62 | text-align: center;
63 | }
64 | .footer-links li {
65 | width: 100%;
66 | }
67 | }
68 |
69 | @media (max-width: 480px) {
70 | .footer .likely__button {
71 | display: none;
72 | }
73 | }
74 |
75 | /* additional */
76 |
77 | .dark .footer .likely .likely__widget {
78 | color: rgba(255, 255, 255, 0.6);
79 | background: rgba(231, 231, 231, 0.1);
80 | }
81 | .dark .footer .likely .likely__widget:hover,
82 | .dark .footer .likely .likely__widget:focus {
83 | background: rgba(231, 231, 231, 0.2);
84 | }
85 |
--------------------------------------------------------------------------------
/src/css/globals.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | html {
8 | /* fallback */
9 | font-family: "PT Serif";
10 | -webkit-font-smoothing: antialiased;
11 | -webkit-text-size-adjust: none;
12 | font-family: var(--font-serif);
13 | line-height: 1.4em;
14 | font-size: 18px;
15 | color: var(--text-color);
16 | background: var(--background-color);
17 | min-width: 320px;
18 | }
19 |
20 | body {
21 | background-color: var(--background-color);
22 | }
23 |
24 | body.dark {
25 | --background-color: var(--dark);
26 | --text-color: var(--light);
27 | --link-color: var(--blue-light);
28 | --link-border-color: var(--blue-transparent-light);
29 | --link-border-color-visited: var(--purple-transparent-light);
30 | --link-border-color-hover: var(--red-transparent-light);
31 | --link-color-visited: var(--purple-light);
32 | --active-nav: var(--red-light);
33 | --figcaption: var(--grey-5-light);
34 | --blockquote-background: var(--gun-powder);
35 | --blockquote-before-background: var(--grey-1-light);
36 | --mark-color: var(--light);
37 | --footer-links-color: var(--grey-5-light);
38 | --footer-links-color-hover: var(--light);
39 | --footer-links-border-color: var(--grey-2-light);
40 | --footer-links-border-color-hover: var(--grey-3-light);
41 | --table-border-color: var(--grey-05-light);
42 | }
43 |
44 | h1,
45 | h2,
46 | h3,
47 | h4,
48 | h5,
49 | h6 {
50 | /* fallback */
51 | font-family: "PT Sans", sans-serif;
52 |
53 | font-family: var(--font-sans-serif);
54 | }
55 |
56 | h1 {
57 | font-size: 2.45rem;
58 | line-height: 2.8rem;
59 | margin-bottom: 0.6rem;
60 | }
61 |
62 | h2 {
63 | font-size: 1.75rem;
64 | line-height: 2.05rem;
65 | margin-bottom: 0.6rem;
66 | }
67 |
68 | h3 {
69 | margin: 1rem 0 -1rem;
70 | font-size: 1rem;
71 | }
72 |
73 | p {
74 | margin-top: 1rem;
75 | }
76 |
77 | h2 + p,
78 | h1 + p {
79 | margin-top: 0;
80 | }
81 |
82 | blockquote {
83 | /* fallback */
84 | background: #f7f5ec;
85 |
86 | margin: 1.6rem 0;
87 | padding: 1.3rem 3rem 1.8rem;
88 | display: block;
89 | background: var(--blockquote-background);
90 | position: relative;
91 | }
92 | blockquote:last-child {
93 | margin-bottom: 0;
94 | }
95 |
96 | blockquote:before {
97 | content: "«";
98 | position: absolute;
99 | left: 1rem;
100 | top: 0.9rem;
101 | color: var(--blockquote-before-background);
102 | font-size: 3.2rem;
103 | }
104 |
105 | blockquote p:first-child {
106 | margin-top: 0;
107 | }
108 |
109 | figure {
110 | margin-bottom: 3rem;
111 | }
112 |
113 | figure.is-in-content,
114 | .section figure.is-in-content,
115 | figure.is-mobile-content,
116 | .section figure.is-mobile-content {
117 | margin: 1.5rem auto 2rem;
118 | max-width: 500px;
119 | }
120 |
121 | figure.is-mobile-content,
122 | .section figure.is-mobile-content {
123 | max-width: 320px;
124 | }
125 |
126 | figcaption {
127 | font-style: normal;
128 | font-size: 0.8rem;
129 | line-height: 1.2em;
130 | padding-top: 0.3rem;
131 | color: var(--figcaption);
132 | text-align: center;
133 | font-family: var(--font-sans-serif);
134 | }
135 |
136 | mark {
137 | color: var(--mark-color);
138 | display: block;
139 | margin: 0;
140 | padding: 1.8rem 0 1.5rem 3rem;
141 | font-size: 1.6rem;
142 | line-height: 1.3em;
143 | background: none;
144 | font-family: var(--font-serif);
145 | }
146 |
147 | .is-decorated img {
148 | box-shadow: 0 1px 2px var(--grey-2);
149 | }
150 |
151 | a {
152 | color: var(--link-color);
153 | text-decoration: none;
154 | border-bottom: 1px solid var(--link-border-color);
155 | }
156 | a:visited {
157 | color: var(--link-color-visited);
158 | border-bottom-color: var(--link-border-color-visited);
159 | }
160 | a:hover {
161 | color: var(--red);
162 | border-bottom-color: var(--link-border-color-hover);
163 | }
164 |
165 | .is-visually-hidden {
166 | position: absolute !important;
167 | clip: rect(1px, 1px, 1px, 1px);
168 | padding: 0 !important;
169 | border: 0 !important;
170 | height: 1px !important;
171 | width: 1px !important;
172 | overflow: hidden;
173 | }
174 |
175 | .smallcaps {
176 | font-size: 0.875em;
177 | letter-spacing: 0.15em;
178 | margin-right: -0.15em;
179 | text-transform: uppercase;
180 | }
181 |
182 | .force-full-width {
183 | width: 100%;
184 | }
185 |
186 | @media (max-width: 980px) {
187 | html {
188 | font-size: 16px;
189 | }
190 | }
191 |
192 | @media (max-width: 800px) {
193 | mark {
194 | padding: 1.5rem 0 1.5rem 2rem;
195 | }
196 |
197 | figcaption {
198 | font-size: 0.9rem;
199 | }
200 | }
201 |
202 | @media (max-width: 640px) {
203 | html {
204 | font-size: 14px;
205 | line-height: 1.5em;
206 | }
207 |
208 | blockquote {
209 | padding: 1.1rem 1rem 1.3rem 2rem;
210 | margin: 1.4rem 0;
211 | }
212 |
213 | blockquote:before {
214 | left: 0.6rem;
215 | top: 0.8rem;
216 | font-size: 2.2rem;
217 | }
218 |
219 | mark {
220 | font-size: 1.3rem;
221 | line-height: 1.3em;
222 | padding: 1.3rem 0 0.8rem 2rem;
223 | }
224 |
225 | mark:last-child {
226 | padding-bottom: 0;
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/src/css/grid.css:
--------------------------------------------------------------------------------
1 | .center {
2 | max-width: 1400px;
3 | margin: 0 auto;
4 | padding: 0 1.5rem;
5 | width: 100%;
6 | }
7 |
8 | .center--narrow {
9 | max-width: 700px;
10 | }
11 |
12 | .grid {
13 | position: relative;
14 | display: flex;
15 | flex-wrap: wrap;
16 | }
17 |
18 | .column {
19 | flex: 1;
20 | }
21 |
22 | .column--left {
23 | /* fallback */
24 | width: 200px;
25 | max-width: 200px;
26 |
27 | width: var(--nav-width);
28 | max-width: var(--nav-width);
29 |
30 | align-self: flex-start;
31 | position: -webkit-sticky;
32 | position: sticky;
33 | top: 0;
34 | }
35 |
36 | .column--right {
37 | /* fallback */
38 | max-width: 240px;
39 | width: 28%;
40 | padding-left: 60px;
41 |
42 | max-width: var(--right-column-max-width);
43 | width: var(--right-column-width);
44 | padding-left: var(--right-column-padding);
45 | padding-top: 2.9rem;
46 | }
47 |
48 | .column--third {
49 | width: 33%;
50 | }
51 |
52 | @media (max-width: 1060px) {
53 | .center {
54 | padding: 0 1.2rem;
55 | }
56 | .center--narrow {
57 | max-width: 850px;
58 | padding: 0 2.4rem;
59 | }
60 | }
61 |
62 | @media (max-width: 900px) {
63 | .center--narrow {
64 | max-width: 100%;
65 | }
66 | .column--center,
67 | .column--left {
68 | display: block;
69 | position: relative;
70 | width: 100%;
71 | max-width: 100%;
72 | flex: auto;
73 | }
74 | .column--left {
75 | padding-left: 1.2rem;
76 | }
77 | }
78 |
79 | @media (max-width: 800px) {
80 | .center--narrow {
81 | padding: 0 1.2rem;
82 | }
83 | .center .center,
84 | .column--left {
85 | padding: 0;
86 | }
87 |
88 | .column {
89 | display: block;
90 | position: relative;
91 | width: 100%;
92 | max-width: 100%;
93 | flex: auto;
94 | }
95 | .column--left {
96 | position: static;
97 | }
98 | .column--right {
99 | padding-left: 0;
100 | padding-top: 0;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/css/header.css:
--------------------------------------------------------------------------------
1 | .header {
2 | position: relative;
3 | min-height: 540px;
4 | display: flex;
5 |
6 | background-color: var(--header-background);
7 | background-image: url(../img/sad-frontender.jpg);
8 | background-repeat: no-repeat;
9 | background-position: center;
10 | background-size: cover;
11 |
12 | color: white;
13 | text-shadow: 1px 2px 2px var(--grey-3);
14 | font-size: 2rem;
15 | line-height: 1.3em;
16 | text-align: center;
17 | }
18 |
19 | @supports (height: 100vh) {
20 | .header {
21 | height: 100vh;
22 | }
23 | }
24 |
25 | .header h1 {
26 | font-size: 6rem;
27 | line-height: 1em;
28 | margin-bottom: 2.5rem;
29 | }
30 |
31 | .header .content {
32 | padding: 20px 60px;
33 | margin: auto;
34 | font-family: var(--font-sans-serif);
35 | }
36 |
37 | .header .copyright {
38 | color: rgba(255, 255, 255, 0.4);
39 | position: absolute;
40 | bottom: 10px;
41 | right: 10px;
42 | font-size: 0.6rem;
43 | line-height: 1.2em;
44 | text-align: right;
45 | width: 70%;
46 | }
47 |
48 | @media (max-width: 800px) {
49 | .header h1 {
50 | font-size: 3.5rem;
51 | margin-bottom: 1.2rem;
52 | }
53 | }
54 |
55 | @media (max-width: 640px) {
56 | .header {
57 | font-size: 1.2rem;
58 | line-height: 1.3em;
59 | }
60 | .header h1 {
61 | font-size: 2.2rem;
62 | }
63 | .header .content {
64 | padding: 0 25px;
65 | max-width: 380px;
66 | }
67 | .header .copyright {
68 | font-size: 0.8rem;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/css/nav.css:
--------------------------------------------------------------------------------
1 | .nav {
2 | position: relative;
3 | padding: 3.5rem 0 2rem;
4 | max-height: 100vh;
5 | overflow: auto;
6 | top: 0;
7 | font-size: 0.9rem;
8 | line-height: 1.25em;
9 | font-family: var(--font-sans-serif);
10 | background-color: var(--background-color);
11 | }
12 |
13 | .nav ul,
14 | .nav li {
15 | list-style: none;
16 | }
17 |
18 | .nav li {
19 | margin-bottom: 0.6rem;
20 | }
21 |
22 | .nav a {
23 | text-decoration: none;
24 | }
25 |
26 | .nav-toggle {
27 | margin-bottom: 1.2rem;
28 | }
29 |
30 | @media (min-width: 901px) {
31 | .nav a.is-active {
32 | border: 0;
33 | color: var(--active-nav);
34 | cursor: default;
35 | }
36 | }
37 |
38 | @media (max-width: 900px) {
39 | .nav {
40 | padding-top: 0;
41 | position: relative;
42 | max-height: 100000vh;
43 | height: auto;
44 | width: 100%;
45 | }
46 |
47 | .nav {
48 | font-size: 1rem;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/css/section.css:
--------------------------------------------------------------------------------
1 | .section {
2 | padding: 3.5rem 0 1rem;
3 | display: flex;
4 | background-color: var(--background-color);
5 | color: var(--text-color);
6 | }
7 |
8 | .section.has-no-padding {
9 | padding-top: 0;
10 | }
11 |
12 | .preface,
13 | .afterwords {
14 | padding: 5rem 0 3rem;
15 | min-height: 100vh;
16 | }
17 | .preface .center,
18 | .afterwords .center {
19 | margin: auto;
20 | }
21 |
22 | .section figure {
23 | max-width: 100%;
24 | }
25 |
26 | .section figure img {
27 | max-width: 100%;
28 | }
29 |
30 | .section .is-inside {
31 | margin-top: -1.6rem;
32 | }
33 |
34 | .section-link {
35 | font-size: 0.6em;
36 | display: inline-block;
37 | vertical-align: top;
38 | border: 0;
39 | margin: 0 0 0 0.1rem;
40 | padding: 0 0 0 0.1rem;
41 | width: 2rem;
42 | height: 2rem;
43 | line-height: 2.3rem;
44 | text-align: center;
45 | border-radius: 50%;
46 | box-sizing: border-box;
47 | opacity: 0;
48 | transition: opacity 0.1s, background 0.2s;
49 | will-change: opacity, background;
50 | }
51 | h2:hover .section-link {
52 | opacity: 1;
53 | }
54 | .section-link:hover {
55 | background: var(--light-brown);
56 | }
57 |
58 | .tutorials,
59 | .caption {
60 | font-size: 0.8rem;
61 | line-height: 1.3em;
62 | }
63 |
64 | .caption {
65 | margin-bottom: 0.3rem;
66 | font-weight: 700;
67 | font-family: var(--font-sans-serif);
68 | }
69 |
70 | .tutorials li {
71 | margin-bottom: 0.6rem;
72 | }
73 | .tutorials li.list-section {
74 | padding-top: 0.4rem;
75 | }
76 |
77 | .tutorials + .caption {
78 | margin-top: 2rem;
79 | }
80 |
81 | .insert {
82 | padding: 1.8rem 0;
83 | }
84 | .insert:last-child {
85 | padding-bottom: 0;
86 | }
87 |
88 | .insert .column {
89 | width: 50%;
90 | padding: 0 1rem 0 1.5rem;
91 | }
92 |
93 | .insert .caption,
94 | .insert .tutorials {
95 | font-size: 0.9rem;
96 | line-height: 1.3rem;
97 | }
98 |
99 | .section .tableContainer {
100 | margin: 0.5rem 0 1.7rem;
101 | }
102 |
103 | .section table {
104 | padding: 0;
105 | border-collapse: collapse;
106 | font-size: 0.9rem;
107 | line-height: 1.3em;
108 | width: 100%;
109 | }
110 |
111 | .section td {
112 | padding: 0.6rem 1rem 0.7rem;
113 | margin: 0;
114 | border: 0;
115 | vertical-align: top;
116 | border-bottom: 1px solid var(--table-border-color);
117 | border-right: 1px solid var(--table-border-color);
118 | width: 50%;
119 | }
120 |
121 | .section td:last-child {
122 | border-right: 0;
123 | }
124 | .section tr:last-child td {
125 | border-bottom: 0;
126 | }
127 |
128 | @media (max-width: 1060px) {
129 | .caption,
130 | .tutorials,
131 | .insert .caption,
132 | .insert .tutorials {
133 | line-height: 1.4em;
134 | }
135 | }
136 |
137 | @media (min-width: 801px) {
138 | .section figure.is-mobile-content {
139 | display: none;
140 | }
141 | }
142 |
143 | @media (max-width: 900px) {
144 | .section-link {
145 | opacity: 1;
146 | }
147 | }
148 |
149 | @media (max-width: 800px) {
150 | .section {
151 | padding-top: 3rem;
152 | }
153 |
154 | .section .is-inside {
155 | margin-top: 0;
156 | }
157 |
158 | .caption,
159 | .tutorials,
160 | .insert .caption,
161 | .insert .tutorials {
162 | font-size: 1rem;
163 | margin-left: 2rem;
164 | }
165 |
166 | aside .tutorials:last-child {
167 | margin-bottom: -0.4rem;
168 | }
169 |
170 | aside .caption:first-child,
171 | aside figure + .caption {
172 | margin-top: 1.5rem;
173 | }
174 |
175 | .insert .caption {
176 | font-weight: 700;
177 | }
178 |
179 | .insert .column {
180 | padding-left: 0;
181 | padding-bottom: 0;
182 | margin-bottom: 0;
183 | }
184 |
185 | .insert {
186 | padding: 1.8rem 0 1rem;
187 | }
188 |
189 | aside figure {
190 | display: none;
191 | }
192 |
193 | .section.preface,
194 | .section.afterwords {
195 | min-height: 200px;
196 | padding: 4rem 0 2rem;
197 | }
198 | }
199 |
200 | @media (max-width: 640px) {
201 | .section {
202 | padding-bottom: 0;
203 | }
204 |
205 | .insert .column {
206 | width: 100%;
207 | padding: 0;
208 | }
209 |
210 | .insert .column + .column {
211 | margin-top: 1.5rem;
212 | }
213 |
214 | .tutorials + .caption {
215 | margin-top: 1.5rem;
216 | }
217 | }
218 |
219 | @media (max-width: 540px) {
220 | .section .tableContainer {
221 | margin-left: -1.2rem;
222 | margin-right: -1.2rem;
223 | }
224 | .section td {
225 | padding-left: 1.2rem;
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/src/css/style.css:
--------------------------------------------------------------------------------
1 | @import url(../../node_modules/ilyabirman-likely/release/likely.min.css);
2 | @import url(../../node_modules/typograf/dist/typograf.css);
3 |
4 | @import url(./themes/_light.css);
5 | @import url(./themes/_dark.css);
6 | @import url(./_constants.css);
7 |
8 | @import url(./globals.css);
9 | @import url(./grid.css);
10 |
11 | @import url(./header.css);
12 | @import url(./footer.css);
13 | @import url(./nav.css);
14 | @import url(./toggle.css);
15 |
16 | @import url(./section.css);
17 | @import url(./adornment.css);
18 | @import url(./checklist.css);
19 |
--------------------------------------------------------------------------------
/src/css/themes/_breakpoints.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Breakpoints used in the project:
3 | * - 480px
4 | * - 540px
5 | * - 640px
6 | * - 900px
7 | * - 980px
8 | * - 1060px
9 | */
10 |
--------------------------------------------------------------------------------
/src/css/themes/_dark.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --grey-05-light: rgba(255, 255, 255, 0.05);
3 | --grey-1-light: rgba(255, 255, 255, 0.1);
4 | --grey-2-light: rgba(255, 255, 255, 0.2);
5 | --grey-3-light: rgba(255, 255, 255, 0.3);
6 | --grey-5-light: rgba(255, 255, 255, 0.5);
7 |
8 | --gun-powder: #44475a;
9 | --purple-light: #bd93f9;
10 | --blue-light: #00a1fe;
11 | --red-light: #ff5555;
12 |
13 | --purple-transparent-light: rgba(189, 147, 249, 0.05);
14 | --blue-transparent-light: rgba(0, 139, 254, 0.2);
15 | --red-transparent-light: rgba(251, 51, 71, 0.2);
16 |
17 | --dark: #282a36;
18 | --light: #f8f8f2;
19 | }
20 |
--------------------------------------------------------------------------------
/src/css/themes/_light.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --grey-05: rgba(0, 0, 0, 0.05);
3 | --grey-1: rgba(0, 0, 0, 0.1);
4 | --grey-2: rgba(0, 0, 0, 0.2);
5 | --grey-3: rgba(0, 0, 0, 0.3);
6 | --grey-5: rgba(0, 0, 0, 0.5);
7 |
8 | --purple: #542189;
9 | --blue: #0000fe;
10 | --red: #fb3347;
11 | --brown: #887744;
12 | --light-brown: #f7f5ec;
13 |
14 | --purple-transparent: rgba(84, 33, 137, 0.1);
15 | --blue-transparent: rgba(0, 0, 254, 0.1);
16 | --red-transparent: rgba(251, 51, 71, 0.1);
17 |
18 | --white: white;
19 | --black: black;
20 | }
21 |
--------------------------------------------------------------------------------
/src/css/toggle.css:
--------------------------------------------------------------------------------
1 | /* created: Joseph Shenton @TeamiHackify */
2 | /* adapted: Tagir Almasov @tagir-a */
3 | .toggle {
4 | display: flex;
5 | align-items: center;
6 | }
7 |
8 | .toggle input {
9 | position: absolute;
10 | width: 1px;
11 | height: 1px;
12 | margin: -1px;
13 | padding: 0;
14 | overflow: hidden;
15 | border: 0;
16 | clip: rect(0 0 0 0);
17 | }
18 |
19 | .toggle label {
20 | color: var(--text-color);
21 | display: flex;
22 | align-items: center;
23 | cursor: pointer;
24 | }
25 |
26 | .toggle-label::before {
27 | content: "";
28 | background: url("../img/sun.svg");
29 | width: 18px;
30 | height: 18px;
31 | margin-right: 7px;
32 | }
33 |
34 | .toggle-label--crescent::before {
35 | background: url("../img/crescent.svg");
36 | margin-left: 7px;
37 | margin-right: 0;
38 | }
39 |
40 | .toggle-control + .toggle-button {
41 | width: 40px;
42 | height: 20px;
43 | border: 2px solid var(--toggle-border);
44 | }
45 |
46 | .toggle-control + .toggle-button::after {
47 | position: relative;
48 | width: 50%;
49 | height: 100%;
50 | }
51 |
52 | .toggle-control + .toggle-button::after {
53 | left: 0;
54 | }
55 |
56 | .toggle-control:checked + .toggle-button::after {
57 | left: 50%;
58 | }
59 |
60 | .toggle-control + .toggle-button {
61 | padding: 2px;
62 | border: 2px solid var(--toggle-background);
63 | border-radius: 2em;
64 | }
65 |
66 | .toggle-control + .toggle-button::after {
67 | transition: all 0.2s ease;
68 | background: var(--toggle-background);
69 | content: "";
70 | border-radius: 1em;
71 | }
72 |
73 | .toggle-control:focus + .toggle-button {
74 | outline: auto;
75 | }
76 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
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 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/js/nav.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | // Detect passive event support:
3 | let supportsPassive = false;
4 | try {
5 | const opts = Object.defineProperty({}, "passive", {
6 | get() {
7 | supportsPassive = { passive: true };
8 | },
9 | });
10 | window.addEventListener("test", null, opts);
11 | } catch (e) {}
12 |
13 | // Detect history API support for hash changes:
14 | const supportsHistoryApi =
15 | typeof history !== "undefined" && !!history.pushState;
16 |
17 | // Library-like utilities:
18 | function throttle(callee, timeout = 250) {
19 | let timer = null;
20 |
21 | return function perform(...args) {
22 | if (timer) return;
23 |
24 | timer = setTimeout(() => {
25 | callee(...args);
26 | clearTimeout(timer);
27 | timer = null;
28 | }, timeout);
29 | };
30 | }
31 |
32 | function getElementOffsetTop(node) {
33 | if (!node) return 0;
34 | const rect = node.getBoundingClientRect();
35 | return rect.top + window.pageYOffset;
36 | }
37 |
38 | function currentHash() {
39 | return location.hash.replace("#", "");
40 | }
41 |
42 | // Main script:
43 | const sections = document.getElementsByClassName("section");
44 | const headings = document.getElementsByClassName("section-link");
45 | const nav = document.getElementById("nav");
46 |
47 | let shouldWatchScroll = true;
48 | let sectionOffsets;
49 | updateSectionOffsets();
50 |
51 | window.addEventListener("scroll", handleScroll, supportsPassive);
52 | window.addEventListener("resize", throttle(updateSectionOffsets));
53 |
54 | nav.addEventListener("click", handleLinkClick);
55 | Array.from(headings).forEach((el) => {
56 | el.addEventListener("click", handleLinkClick);
57 | });
58 |
59 | function isNarrowScreen() {
60 | const minDesktopWidth = 801;
61 | return window.innerWidth < minDesktopWidth;
62 | }
63 |
64 | function updateSectionOffsets() {
65 | sectionOffsets = [...sections].map(getElementOffsetTop);
66 | }
67 |
68 | function handleLinkClick(e) {
69 | if (!e.target.closest) return;
70 |
71 | const link = e.target.closest("a");
72 | if (!link) return;
73 |
74 | e.preventDefault();
75 | const sectionName = link.getAttribute("href").replace("#", "");
76 | scrollToSection(sectionName);
77 | }
78 |
79 | function scrollToSection(sectionName) {
80 | const section = document.getElementById(sectionName);
81 | if (!section || !sectionName) return;
82 |
83 | updateActiveLink(sectionName);
84 |
85 | shouldWatchScroll = false;
86 | setTimeout(() => {
87 | shouldWatchScroll = true;
88 | location.hash = sectionName;
89 | }, 500);
90 |
91 | window.scrollTo({
92 | top: getElementOffsetTop(section),
93 | behavior: "smooth",
94 | });
95 | }
96 |
97 | function handleScroll() {
98 | if (!shouldWatchScroll || isNarrowScreen()) return;
99 |
100 | const section = findCurrentSection();
101 | const id = section ? section.getAttribute("id") : null;
102 |
103 | if (!id) return;
104 | silentlyChangeHash(id);
105 | updateActiveLink(id);
106 | }
107 |
108 | function findCurrentSection() {
109 | const currentPosition = window.scrollY;
110 | return sectionOffsets.reduce(
111 | (section, offset, index) =>
112 | offset <= currentPosition ? sections[index] : section,
113 | null
114 | );
115 | }
116 |
117 | function updateActiveLink(id) {
118 | const activeLinkClassName = "is-active";
119 | const activeLinkQuery = `.nav a.${activeLinkClassName}`;
120 |
121 | const currentActive = document.querySelector(activeLinkQuery);
122 | const nextActive = document.querySelector(`[href="#${id}"]`);
123 | if (currentActive === nextActive) return;
124 |
125 | currentActive && currentActive.classList.remove(activeLinkClassName);
126 | nextActive && nextActive.classList.add(activeLinkClassName);
127 | }
128 |
129 | function silentlyChangeHash(newHash) {
130 | if (!supportsHistoryApi || isNarrowScreen()) return;
131 | if (newHash === currentHash()) return;
132 | history.pushState(null, null, `#${newHash}`);
133 | }
134 | })();
135 |
--------------------------------------------------------------------------------
/src/js/theme-toggle.js:
--------------------------------------------------------------------------------
1 | (function setupThemeToggler() {
2 | const toggle = document.getElementById("toggle");
3 |
4 | toggle.addEventListener("change", () =>
5 | document.body.classList.toggle("dark")
6 | );
7 |
8 | const darkThemeQuery = "(prefers-color-scheme: dark)";
9 | const matchMedia = window.matchMedia;
10 | if (matchMedia && matchMedia(darkThemeQuery).matches) {
11 | toggle.click();
12 | }
13 | })();
14 |
--------------------------------------------------------------------------------
/src/sections/afterwords.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Что дальше? 🔗
4 |
Дальше — развиваться и делать классные вещи в вебе. Мы собрали все советы в чеклист . Распечатай его, пусть будет на виду.
5 |
Главное не останавливайся, потому что всегда есть, куда расти. И помни: работа не должна быть каторгой, фронтендеры не должны быть грустными.
6 |
P.S. Баги, опечатки, идеи и предложения присылай на почту или на Гитхаб .
7 |
P.P.S. Если хочется поддержать проект или поблагодарить авторов, напиши нам письмо , пошарь книгу в соцсетях или задонать на кофе . Нам будет приятно :–)
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/sections/backender.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Тоже бекендер 🔗
6 |
7 |
Знание бекенда поможет понять, как устроен проект на сервере. Сможешь оптимизировать логику запросов, улучшить загрузку страниц, оптимизировать загрузку статики на фронт.
8 |
9 |
36 |
37 |
38 |
39 | Что делать
40 |
41 | Пробовать писать серверные приложения
42 | Учиться работать с базами данных
43 | Улучшать интерфейсы своих функций и методов
44 | Оптимизировать общение клиента с сервером
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/sections/conversation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Как сделать, чтобы тебя услышали 🔗
6 |
Один из главных инструментов в работе фронтендеров — умение общаться с командой и обсуждать проблемы.
7 |
8 |
Проблемы можно и нужно обсуждать с дизайнером и командой
9 |
10 |
Чтобы объяснить проблему дизайнерам, с ними нужно поговорить. Чтобы обсудить интерфейс функции с бекендерами — тоже. Что-то узнать у менеджеров — снова надо говорить. Если ты умеешь общаться, ты уже на порядок круче других.
11 |
12 |
Я бы и с радостью, но не выходит...
13 |
14 |
Да, переговорам всегда будет что-то мешать. Дизайнер устал и не выходит на связь, у бекендера нет времени, менеджеру лень. Чтобы удалось договориться с собеседником, он должен видеть пользу для себя в обсуждении.
15 |
16 |
Собеседнику важно видеть пользу для себя от переговоров
17 |
18 |
Подскажи, что система сеток разгрузит дизайнеров от рисования контентных страниц, и ты самостоятельно сможешь их наполнить. Покажи бекендерам, что с документированным API тебе не придётся через раз спрашивать, как работает бекенд. Как только они увидят пользу для себя в обсуждении проблем, время найдётся.
19 |
20 |
В переговорах надо постоянно прокачиваться. Сначала не будет получаться, поэтому надо больше практиковаться.
21 |
22 |
В переговорах надо прокачиваться
23 |
24 |
Проявляй заинтересованность в решении проблем. Если скидывать проблемы на других и ждать решений, ничего не получится. А вот если помогать команде решать проблемы, тебе будут больше доверять и начнут прислушиваться к твоему мнению.
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
36 |
37 | Плохие инструменты не помогают в работе
38 |
39 |
40 | Книги
41 |
44 |
45 | Статьи
46 |
55 |
56 | Видео
57 |
62 |
63 | Что делать
64 |
65 | Обсуждать с дизайнером непонятные места в макетах
66 | Обсуждать с бекендером взаимодействие клиента и сервера
67 | Документировать свой код, учиться точнее выражать мысли
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/sections/conveyor.html:
--------------------------------------------------------------------------------
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 |
26 | Задай себе вопрос: что тебя тут держит? И подумай, стоят ли печеньки того времени, которое
27 | ты убиваешь на это.
28 |
29 |
30 |
Что, просто взять и уйти? А если меня никуда больше не возьмут?
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Надо работать над этим. По человеку судят о результатах его трудов, но они не
40 | заканчиваются на пороге офиса.
41 |
42 |
43 |
44 | Займись опенсорсом, заведи пет-проект, пиши и переводи статьи. Если ты что-то делаешь вне
45 | офиса, ты уже заметнее других фронтендеров.
46 |
47 |
48 |
49 | Но даже если опенсорс и пет-проекты тебе не вкатывают, писать не получается, а с докладами
50 | выступать боишься — сделай что-то крутое внутри проекта из офиса.
51 |
52 |
53 |
54 | Принесли макет, и там должна быть анимация? Сделай такую анимацию, чтобы её потом не
55 | стыдно было показать у себя на сайте. Сделай ленивую загрузку картинок, чтобы страница
56 | загружалась мгновенно. Упорись по доступности, чтобы по странице можно было ходить с
57 | микроволновки. Да, блин, что угодно вообще. Выбери и фигачь.
58 |
59 |
60 |
61 | Найдёшь что-то своё — делай, сделай круче, сохрани и хвастайся. Сделай так, чтобы распирало
62 | от гордости. Хвастаться работой вообще очень полезно. Чем чаще показываешь работу, тем
63 | больше фидбека и радости оттого, что сделал.
64 |
65 |
66 |
67 | Избавься от рутины, а потом занимайся тем, что нравится. Повезёт — другие ребята из
68 | команды захотят так же, найдёте с ними общий язык. Не повезёт, и будешь искать другую
69 | работу — у тебя будет больше шансов её найти, если есть годные штуки за плечами.
70 |
71 |
72 |
73 | А если мне ничего не нравится? Я, может, вообще делаю это всё только ради денег
74 |
75 |
76 |
77 | Ну как-то же тебя сюда занесло, что-то привлекло. Вспомни, что именно, откопай и используй. У
78 | тебя не так много времени, зачем тратить его на то, что не нравится, если можно тратить
79 | его с пользой и удовольствием.
80 |
81 |
82 |
83 |
84 | Статьи
85 |
92 |
93 | Видео
94 |
99 |
100 | Что делать
101 |
102 | Задавать себе вопросы: «не фигнёй ли я занимаюсь?», «что меня здесь держит?»
103 | Разбираться с мотивацией и искать то, что приносит в работе удовольствие
104 | Делиться кайфовыми вещами с сообществом
105 | Если совсем некуда деваться, менять проект или команду
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/src/sections/deisgner.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Фронтендер — тоже дизайнер 🔗
6 |
7 |
Не зацикливайся на программировании, осваивай смежные области тоже. Пробуй вникать в дизайн, с ним фронтендеры сталкиваются в работе каждый день.
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 | Фронтендер тоже дизайнер
19 |
20 |
21 |
Разница в понимании терминов и понятий ведёт к непониманию между фронтендером и дизайнером. Договариваться об одном и том же разными словами — тяжело, начнутся жалобы «ну я ж спрашивал, как это должно быть, мне сказали так». Чтобы понимать друг друга, надо говорить на одном языке.
22 |
23 |
Типографика и вёрстка
24 |
Научишься подбирать правильные отступы и интерлиньяж. Сможешь сверстать новый блок без помощи дизайнера, выстроить вертикальный ритм на странице. Чем стройнее типографика, тем проще читать текст. Это делает сайт или приложение удобнее в использовании.
25 |
26 |
45 |
46 |
Анимации
47 |
Научишься управлять вниманием пользователя и расставлять акценты на странице. Сможешь отличать уместные анимации от неуместных. Узнаешь, как создавать простые в реализации, но красивые анимации.
48 |
49 |
50 |
51 |
Видео
52 |
55 |
56 |
Статьи
57 |
61 |
62 |
71 |
72 |
73 |
Интерфейс и представление информации
74 |
Поймёшь, как правильно подписать новый лейбл в форме. Узнаешь, зачем нужны ховеры. Не придётся просить дизайнера разрисовать все состояния кнопок и полей.
75 |
76 |
77 |
78 |
Книги
79 |
85 |
86 |
Видео
87 |
93 |
94 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
116 |
117 | Фронтендер тоже дизайнер
118 |
119 |
120 | Что делать
121 |
122 | Дизайнить простые страницы и промо-страницы своих проектов самостоятельно
123 | Пробовать разные инструменты для создания анимаций, искать лучшие
124 | Если в макете не указано, как что-то должно работать, придумывать самостоятельно и утверждать решения у дизайнера
125 | Править интерфейсные ошибки в собственном проекте и не допускать в будущих
126 |
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/src/sections/editor.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Тоже редактор 🔗
6 |
7 |
Хороший текст научит подписывать элементы на странице, править заголовки, опечатки и ошибки, формулировать мысли. Текст — это эффективное средство коммуникации. Пользователи приходят за ним на сайт, а компании ради него нанимают UX -писателей в штат.
8 |
9 |
10 |
11 |
Статьи
12 |
17 |
18 |
Видео
19 |
22 |
23 |
31 |
32 |
33 |
34 |
35 | Что делать
36 |
37 | Писать рассказы о проектах для резюме или портфолио
38 | Проверять подписи полей перед выпуском в продакшен
39 | Перечитывать заголовки и предлагать формулировки лучше, если можно
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/sections/engineer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Тоже инженер 🔗
6 |
7 |
Если думать как инженер, будешь видеть решение комплекса проблем, а не одной конкретной. Научишься решать задачи с учётом возможных проблем в будущем, разбивать сложные задачи на простые.
8 |
9 |
10 |
11 |
Книги
12 |
16 |
17 |
Видео
18 |
24 |
25 |
34 |
35 |
36 |
37 |
38 | Что делать
39 |
40 | Продумывать решение задачи комплексно, расписывать задачи на бумаге
41 | Думать над расширяемостью и возможными проблемами в будущем
42 | Анализировать старые проекты
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/sections/header.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/sections/kiss.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Чем проще — тем лучше 🔗
6 |
7 |
Сделать идеальный проект нельзя, поэтому нужно уметь видеть важное и делать это в первую очередь. Фронтендерам полезно отличать критичные задачи от некритичных, чтобы успеть сделать важное к сроку.
8 |
9 |
Чтобы уметь докапываться до правды, надо уметь вести переговоры и понимать полезное действие продукта. Иногда фронтендеры просто не в состоянии успеть сделать всё запланированное. Поэтому им важно знать, что из задуманного должно быть в релизе обязательно.
10 |
11 |
Продукты растут и развиваются итеративно. За итерацию продукт наращивает мясо из фич. Поэтому код придётся переписывать и доделывать, так это работает.
12 |
13 |
Но не всегда чем больше фич, тем лучше. Чем продукт проще, тем проще его поддерживать и тем он понятнее для пользователей. Поэтому принцип KISS полезен не только для программистов, но и для продуктов.
14 |
15 |
Если видишь проблему в дизайне или коде, обсуди с командой. Поддержка плохих или слишком сложных решений в будущем будет стоить больше времени, денег и нервов. Тут речь и о дизайне, и о фичах для пользователей. Видишь, что сложно и неудобно — скажи.
16 |
17 |
Помни, что все делают одно дело. Работать должно быть проще. Пусть время тратится не на дебагинг и отладку, а на сам продукт.
18 |
19 |
20 |
21 | Статьи
22 |
26 |
27 | Что делать
28 |
29 | Рефакторить плохой код, даже если он не твой
30 | Анализировать код старых проектов, выделять части, которые можно упростить
31 | Не молчать, когда видишь слабые или непонятные решения
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/sections/knowledge-and-questions.html:
--------------------------------------------------------------------------------
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 |
26 |
Знания помогают быстрее решать задачи и избегать лишней сложности
27 |
28 |
29 |
30 |
31 |
32 |
33 |
37 |
38 | Вначале думай — потом делай
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
Не уточнишь задачу, прежде чем начать — сядешь переделывать. Не узнаешь, почему в аббревиатуре нужна разрядка — отправят доделывать. Не спросишь, зачем ставить микроразметку, сеошники отправят страницу на доработку.
47 |
48 |
Большая часть доделок у фронтендеров возникает именно из-за непонимания, какой требуется результат. Чем создавать себе лишнюю работу, лучше избавиться от неё заранее.
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 | Вначале думай — потом делай
60 |
61 |
62 |
Вот принесли тебе макет. Выдели непонятные места и спроси о них. Не начинай верстать или программировать, пока не поймёшь, как это должно работать. Если тебе принесли задачу менеджеры, и они не знают деталей, узнай, у кого спрашивать.
63 |
64 |
Да блин... Чё мне больше всех должно быть надо?
65 |
66 |
Да! Это же в твоих интересах сделать сразу нормально и не переделывать. Только тебе не пофиг на твоё личное время :–)
67 |
68 |
Сделать нормально и не переделывать — в твоих интересах
69 |
70 |
71 |
72 |
73 |
74 |
78 |
79 | Сделаешь фигово — придётся переделывать
80 |
81 |
82 |
Именно поэтому переговоры рулят. Без них ты не узнаешь полезных деталей о проекте. Да, собеседники могут отнекиваться, говорить, что у них нет времени. Постарайся найти способ узнать то, что тебе нужно. Пойми задачу и только после этого начинай её решать.
83 |
84 |
Пойми задачу и только после этого начинай её решать
85 |
86 |
Запоминай всё что говорят или объясняют, записывай, веди чеклисты. А если какое-то решение непонятно (вот тебе сказали подвинуть лого на пиксель вниз), сделай, но потом спроси, почему именно так.
87 |
88 |
Не воспринимай критику как оскорбление. Прислушивайся к замечаниям, они помогут быстрее вырасти в новой области.
89 |
90 |
Не воспринимай критику как оскорбление
91 |
92 |
Чем больше ты запомнишь и узнаешь, тем меньше времени тебе понадобится, чтобы освоить что-то ещё. Будет больше шансов попасть в крутую команду .
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
104 |
105 | Сделаешь фигово — придётся переделывать
106 |
107 |
108 | Книги
109 |
114 |
115 | Статьи
116 |
124 |
125 | Видео
126 |
129 |
130 |
131 |
136 |
137 | Что делать
138 |
139 | Не начинать задачу, пока не поймёшь, какой должен быть результат
140 | Ставить себе сроки и укладываться в них без палки менеджера
141 | Просить дизайнера объяснять непонятные вещи в макете
142 | Запоминать (а лучше записывать) объяснения членов команды
143 | Вести чеклисты
144 |
145 |
146 |
147 |
148 |
149 |
150 |
--------------------------------------------------------------------------------
/src/sections/manager.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Тоже менеджер и маркетолог 🔗
7 |
8 |
9 |
10 | Зная полезное действие проекта, проще определять критичные задачи, понимать целевую
11 | аудиторию и браузерную поддержку.
12 |
13 |
14 |
15 | Зная, как работает экономика и как люди принимают решения, будешь понимать, как
16 | пользователи относятся к проекту.
17 |
18 |
19 |
20 |
33 |
34 |
Статьи
35 |
42 |
43 |
44 |
47 |
48 |
49 |
50 |
51 |
52 | Что делать
53 |
54 | Ставить срок на каждую задачу и укладываться в них
55 | Учиться «сделывать»
56 | Не терять фокус во время работы
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/sections/pain.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Боль фронтендеров 🔗
6 |
Так повелось, что верстальщики и фронтендеры души не чают в том, что создают. Свёрстанная страница и написанный код для них — как питомец.
7 |
8 |
И когда приходят злые дизайнеры и говорят, что блок нужно переверстать или убрать со страницы, фронтендеры переживают.
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 | Фронтендеру жалко свой код
20 |
21 |
22 |
Но ведь у меня ушло на это 4 часа в субботу, когда меня в офисе вообще не должно было быть! И так задач немерено, а тут вы ещё со своими пикселями! Мне таски надо закрывать, у меня сроки горят!
23 |
24 |
Им кажется, что их идеи «мочат» и не дают расти. Будто команда сговорилась против них и не понимает, как надо работать. Но это, конечно же, полная дичь.
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
36 |
37 | Фронтендеру жалко свой код
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/sections/preface.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
О чём это и для кого 🔗
4 |
У фронтендеров постоянно бомбит.
5 |
6 |
Дизайнеры просят подвинуть логотип на пиксель вправо, 100500 раз переделывают уже готовые страницы, бекендеры ломают API , тестировщики кидают таски обратно в разработку, менеджеры ставят адовые сроки.
7 |
8 |
Грустные фронтендеры пытаются бороться с этим, но сдаются и утопают в рутине.
9 |
10 |
Мы хотим помочь им справляться с задачами быстрее и качественнее, научиться разделываться с рутиной и получать удовольствие от работы.
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/sections/problem.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Как видят проблему другие 🔗
6 |
Когда фронтендеров представляют, как машину для вёрстки страниц, плохо всем. Фронтендерам кажется, что к их мнению не прислушиваются. Дизайнеры думают, что всем всё надо постоянно объяснять. Никто не доволен.
7 |
8 |
Но фронтендер — специалист. Ты знаешь то, чего могут не знать другие
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 | Используй силу
20 |
21 |
22 |
Твои знания — это сила. Научись использовать её, чтобы к твоему мнению прислушивались. А для этого тебе нужно:
23 |
24 |
Перестать ныть . Когда ноешь, всем кажется, что ты просто отлыниваешь от работы. Будто тебе ничего не стоит переверстать с нуля пару страниц, но тебе просто лень.
25 |
26 |
Начать вникать в то, что делаешь . Когда делаешь задачи с пониманием «для чего», видишь результат своей работы. Вклад становится заметнее — работать приятнее.
27 |
28 |
Да как вникать-то? Никто ж не объясняет. Начинаешь спрашивать — в ответ сразу «иди верстай, не тормози»
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
41 |
42 | Используй силу
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/sections/product.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Фронтендерам платят не за код 🔗
6 |
Задача фронтендеров не в том, чтобы писать код или закрывать таски в Жире. Но понять это сразу им трудно.
7 |
8 |
Моя задача не в том, чтобы писать код? Но мне же за это платят
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 | Когда сказали, что тебе платят не за код
20 |
21 |
22 |
Не за это. Пофиг, сколько строк написано и сколько часов просижено за монитором. Важен результат — то, что код в итоге делает.
23 |
24 |
На самом деле, задача фронтендера — понять, в чём польза проекта, над которым он или она работает. Если код помогает проекту решать задачи пользователей, значит результат есть, и разработчик — молодец. Если результата нет — не молодец.
25 |
26 |
Задача фронтендера — понять, в чём польза проекта
27 |
28 |
Приносить пользу — приятно. Ребята из опенсорса не дадут соврать. Видеть, что результатами работы пользуются люди — клёво.
29 |
30 |
Но часто в больших проектах не все в команде видят свой вклад в результат. Отсюда и все вот эти «после 5 меня в офисе нет», «моё дело — таску закрыть, а чё там дальше пофиг».
31 |
32 |
Фронтендер, дизайнер, бекендер, тестировщик, менеджер, клиент — все равны и делают одно дело : продукт для пользователей.
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
44 |
45 | Когда сказали, что тебе платят не за код
46 |
47 |
48 |
49 |
50 |
51 |
52 |
Та-а-ак, падажжи. Все равны, делают продукт, бла-бла. Я просто страницы верстаю. Мне дают макеты, я делаю...
53 |
54 |
55 |
56 |
57 |
58 |
62 |
63 | Та-а-ак, падажжи
64 |
65 |
66 |
И от твоей вёрстки зависит многое. Фронтендеры — это строители. Архитектор не скажет строителям: «Вот тут мы поставим высотку без фундамента». Они его нафиг пошлют, потому что знают, что высотка рухнет. У фронтендеров в проекте та же роль, что у строителей.
67 |
68 |
Проект с хрупкой вёрсткой не сможет масштабироваться. Приложение с кривой архитектурой загнётся и не выйдет в релиз. Разработчики могут всё это предвидеть. Поэтому важно говорить о проблемах и обсуждать их с командой.
69 |
70 |
Но меня ведь никто не слушает!..
71 |
72 |
73 |
74 |
75 |
76 |
77 |
81 |
82 | Та-а-ак, падажжи
83 |
84 |
85 | Статьи
86 |
89 |
90 | Видео
91 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/src/sections/products-evolve.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Эволюция продукта 🔗
6 |
7 |
Дизайнеры — самые отчаянные лжецы на планете. Если они говорят, что макет не поменяется, — не верь. Дизайн будет меняться. Всегда.
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 | Типичный дизайнер в проекте
19 |
20 |
21 |
Продукты развиваются: какие-то части устаревают, какие-то добавляются.
22 |
23 |
24 |
25 |
26 |
27 |
28 |
Переписывать код придётся постоянно, но это не должно мешать нормально работать
29 |
30 |
Здесь есть две проблемы. Первая — фронтендеры привязываются к тому, что сделали. Поэтому переписывать свёрстанное им больно. Не привязывайся к коду , твоя польза — не написанный код, а работающий продукт. Если он работает лучше, когда страница перевёрстана, то её стоит переверстать.
31 |
32 |
Вторая проблема — невозможно угадать сразу, каким дизайн должен быть . Поэтому дизайнеры строят гипотезы, пробуют решения, а потом изменяют их.
33 |
34 |
Фронтендерам важно построить принципы своей работы так, чтобы изменения не заставляли их переписывать всё с нуля. Умные люди давно напридумывали инструментов и концепций для этого:
35 |
58 |
59 |
Научись работать с этими концепциями и инструментами так, чтобы строить свою работу независимо от остальных.
60 |
61 |
62 |
63 |
64 |
65 |
69 |
70 | «Фронтендеры обновляют зависимости»
71 |
72 |
73 |
Ну например:
74 |
75 |
76 |
77 | Бекендеры поменяли API
78 | Используем паттерн адаптер
79 |
80 |
81 | Дизайнер попросил вернуть фичу двулетней давности
82 | Восстанавливаем фичу из гита
83 |
84 |
85 | Менеджер дал на длинный лендинг всего два дня
86 | Собираем страницу из подготовленных заранее модулей и компонентов
87 |
88 |
89 |
90 |
91 |
Будь гибче. Не делай свою работу хрупкой — много переделывать потом не понравится тебе же.
92 |
93 |
94 |
95 |
96 |
97 |
98 |
102 |
103 | «Фронтендеры обновляют зависимости»
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
Но ведь… макеты же! Там всё было по-другому
112 |
113 |
114 |
115 |
116 |
117 |
122 |
123 | «Но ведь… макеты же!»
124 |
125 |
126 |
Ну бывает :–)
127 | Да, по-другому , и ладно. Макеты — картинки, они быстро устаревают.
128 |
129 |
Фронтендеры решают задачи, дизайнеры тоже. Картинки — это только промежуточный результат, всё тысячу раз изменится до того, как выйдет в продакшен.
130 |
131 |
В смысле пофиг на макеты? От меня требуют пиксель-пёрфект. При этом всё постоянно перерисовывают. И как мне с этим справляться?
132 |
133 |
Проблема тут не конкретно в макетах, а в отсутствии дизайн-системы. Ограничения, правила и договорённости помогут забыть о пиксель-пёрфекте вообще. Один раз настроили вертикальный ритм — используем, настроили шрифты — используем. Вот как делают дизайн крутые ребята .
134 |
135 |
Польза таких систем в том, что никто не путается в цветах и размерах шрифтов, а код переиспользуется по максимуму. Когда под рукой палитра цветов и размеров всего проекта, с ней легко сверяться. Когда есть список компонентов с примерами использования, то понятно какой из них использовать и где.
136 |
137 |
Внедрить дизайн-систему трудно. Никому не хочется делать дополнительную работу. Сначала даже всем кажется, что она только замедляет процесс. Поэтому без переговоров тут — никуда :–)
138 |
139 |
В работе никогда не будет чётких этапов: «нарисовали», «заверстали», «прикрутили» — это нормально
140 |
141 |
Это не значит, что полный редизайн за неделю до релиза — это нормально. Если такое происходит часто, надо поговорить с командой, чтобы как-то поправить процесс.
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
154 |
155 | «Но ведь… макеты же!»
156 |
157 |
158 | Книги
159 |
162 |
163 | Статьи
164 |
170 |
171 |
172 |
176 |
177 | Что делать
178 |
179 | Пользоваться гитом
180 | Осваивать шаблоны проектирования
181 | Разбивать проект на модули, которые можно заменять
182 | Анализировать старые проекты и выделять компоненты и модули
183 | Не воспринимать критику, как оскорбление, прислушиваться к замечаниям
184 |
185 |
186 |
187 |
188 |
189 |
--------------------------------------------------------------------------------
/src/sections/progress.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Развивайся 🔗
6 |
7 |
Окей, лучше знать больше, чтобы работать быстрее и качественнее. Осталось понять, что надо знать. В идеале все смежные области надо хоть немного пощупать. Когда ориентируешься и в дизайне, и в программировании, жить проще.
8 |
9 |
Начни с программирования. Узнавай тонкости языков, с которыми работаешь, изучай в первую очередь основы программирования и алгоритмы, вместо модных фреймворков. Приноси больше пользы. Полезный фронтендер стоит дороже.
10 |
11 |
12 |
13 |
Книги
14 |
20 |
21 |
Видео
22 |
27 |
28 |
29 |
35 |
36 |
50 |
51 |
52 |
53 |
54 | Что делать
55 |
56 | Составлять планы по развитию в программировании
57 | Изучать другие языки: Python, TypeScript, Go
58 | Писать тудушки на новых языках
59 | Составлять планы по развитию не в программировании
60 | Осваивать смежные области знаний
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/src/sections/tester.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Тоже тестировщик 🔗
6 |
7 |
Тесты помогут не пропустить ошибку в продакшн, спокойно спать по ночам и не искать часами баги в коде. С тестами сможешь рефакторить код, не боясь что-то по пути сломать.
8 |
9 |
29 |
30 |
31 |
32 | Что делать
33 |
34 | Писать тесты :–)
35 | Автоматизировать запуск тестов, ставить прекоммит-хуки
36 | Интегрировать тесты в CI
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/sections/you-know-your-shit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
У фронтендеров есть право голоса 🔗
6 |
У всех в команде много работы, срочные задачи, и встречи. На вопросы фронтендеров часто не отвечают. У них копятся задачи, баги, всё ломается, старые браузеры не дают жить. Вселенная будто против, чтобы работалось нормально.
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 | «Тут надо кое-что переверстать»
18 |
19 |
20 |
Здесь сначала надо успокоиться и понять, что ни у кого нет задачи «замочить тебя». Дизайнеру, менеджеру и тестировщику незачем тебя ненавидеть. Но и дизайнер, и менеджер, и клиент переживают за проект и хотят сделать работу качественно.
21 |
22 |
Ни у кого нет задачи «замочить тебя»
23 |
24 |
Поэтому дизайнер придумывает новые решения, которые ему кажутся лучше старых. Отсюда редизайны, перевёрстка и вот это всё.
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
Это не значит, что последнее слово всегда за дизайнером . Вот дизайнер нарисовал красивый селект. Селект должен хорошо работать на мобильных устройствах. Адаптировать его трудно, а времени на проект мало. Выпускать недоделанный контрол для мобилок — нельзя.
34 |
35 |
Можно делать этот селект ночью и ругать дизайнера сквозь зубы. А можно объяснить ограничения платформ, рассказать об известных багах в мобильных браузерах и предложить нативные контролы.
36 |
37 |
Возможно, для мобильных вполне подойдёт стандартный селект. Выиграют все: пользователи получат привычный интерфейс, дизайнер решит задачу, а тебе не придётся сидеть ночью и ругаться.
38 |
39 |
Последнее слово не всегда за дизайнером
40 |
41 |
Другая частая проблема: у дизайнера в макете разные отступы. У одного заголовка 10 пикселей, у другого такого же — 8, у третьего — 11.
42 |
43 |
Какая первая идея приходит в голову? Наложить полурозрачный макет поверх и выровнять все отступы до пикселя. Окей, но потом приходит переделанный макет, а там все отступы снова отличаются на 1–2 пикселя от прежних.
44 |
45 |
Баг это или фича — непонятно. Что ж, на всякий случай снова накладываем макет и переделываем отступы по новой. А потом ещё раз. А потом ещё. А потом спрашиваем, откуда столько рутины :–)
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
57 |
58 | «Тут надо кое-что переверстать»
59 |
60 |
61 |
62 |
63 |
64 |
65 |
Эффективнее было бы перед стартом обговорить с дизайнерами систему отступов, размеров шрифтов и блоков, обсудить сетки. Если в проекте есть система правил и ограничений, и команда им следует, никто не будет путаться в отступах.
66 |
67 |
Это всё замечательно, но у нас не так. Последнее слово всегда за дизайнером, менеджеры тоже на их стороне, фронтендеров у нас не слушают. Сказали сделать так — значит расшибись, но сделай именно так
68 |
69 |
70 |
71 | Видео
72 |
75 |
76 | Статьи
77 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/static/humans.txt:
--------------------------------------------------------------------------------
1 | Hello world!
2 |
3 | Author: Alex Bespoyasov
4 | Email: bespoyasov@me.com
5 | Github: https://github.com/bespoyasov
6 | Telegram: https://telegram.me/bespoyasov
7 | Twitter: https://twitter.com/bespoyasov
8 |
9 | Author: Vadim Yumadilov
10 | Email: yumadilov@gmail.com
11 | Telegram: https://telegram.me/yumadilov
12 | Twitter: https://twitter.com/yumadilov
13 |
14 | Author: Andrey Romanov
15 | Email: me@andrew-r.ru
16 | Github: https://github.com/andrew--r
17 | Telegram: https://telegram.me/andrew_r
18 | Twitter: https://twitter.com/andrew__romanov
19 |
--------------------------------------------------------------------------------
/src/static/img/crescent.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/static/img/resize/djenga.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/djenga.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/do-it-ok.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/do-it-ok.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/do-it-right.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/do-it-right.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/garold-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/garold-1.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/have-done.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/have-done.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/image-harolds.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/image-harolds.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/sceptic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/sceptic.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/table-flip.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/table-flip.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/tools.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/tools.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/waaait.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/waaait.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/wait-but.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/wait-but.jpg
--------------------------------------------------------------------------------
/src/static/img/resize/wait-but.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/wait-but.png
--------------------------------------------------------------------------------
/src/static/img/resize/yoda.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/resize/yoda.jpg
--------------------------------------------------------------------------------
/src/static/img/sad-frontender.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/sad-frontender.jpg
--------------------------------------------------------------------------------
/src/static/img/sun.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/static/img/typical-designer.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/typical-designer.jpg
--------------------------------------------------------------------------------
/src/static/img/typical-designer@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/img/typical-designer@2x.jpg
--------------------------------------------------------------------------------
/src/static/meta/favicon-180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/meta/favicon-180.png
--------------------------------------------------------------------------------
/src/static/meta/favicon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/meta/favicon-192.png
--------------------------------------------------------------------------------
/src/static/meta/favicon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/meta/favicon-512.png
--------------------------------------------------------------------------------
/src/static/meta/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bespoyasov/front-not-pain/490e833dfed4538ca695e3bda9ca1e02beadf920/src/static/meta/favicon.ico
--------------------------------------------------------------------------------
/src/static/meta/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/static/meta/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Фронтенд — это не больно!",
3 | "short_name": "Frontend without Pain!",
4 | "icons": [
5 | {
6 | "src": "/front-not-pain/meta/favicon-192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/front-not-pain/meta/favicon-512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/src/static/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /css
3 | Disallow: /js
4 | Disallow: /img
5 | Disallow: /meta
6 |
--------------------------------------------------------------------------------