= ({ page }) => (
21 |
22 | {page.title}
23 |
24 | );
25 |
26 | const Home: NextPage = () => {
27 | const [showChallengeSolution, setShowChallengeSolution] = useState(false);
28 | const [code, setCode] = useState(`
32 |
33 | Hello
34 | my CSS
35 | World! `);
36 |
37 | return (
38 | <>
39 |
40 | Why CSS Sometimes Sucks
41 |
42 |
43 | Can you predict with 100% confidence what will be the visual result of the following code?
44 |
45 |
46 |
47 | highlight(codeToHighlight, languages.html, 'html')}
50 | onValueChange={(value) => setCode(value)}
51 | />
52 |
53 |
54 | {showChallengeSolution ? (
55 |
60 | ) : (
61 | setShowChallengeSolution(true)}>Show solution
62 | )}
63 |
64 |
65 |
66 |
67 | CSS can be frustrating because it relies on rules and concepts we usually don’t learn and
68 | practice.
69 |
70 |
71 | Not knowing those concepts makes CSS code unpredictable and it can annoy the hell out of
72 | anyone.
73 |
74 |
75 |
76 | This website teaches you those concepts, allowing you to face any CSS issue with
77 | confidence. Straight to the point, information-packed{' '}
78 |
84 | katas
85 | {' '}
86 | (= exercises), will lay a strong theoretical base and put those new skills to practice
87 | with live code editors.
88 |
89 |
90 |
91 | You want to improve your CSS skills? Read and practice the katas in
92 | order. 100% of the content is useful .
93 |
94 |
95 |
96 | You want to master CSS? Try to explain every concept in this{' '}
97 | skills list to someone else. If you succeed in
98 | making it crystal clear, you truly have mastered CSS.
99 |
100 |
101 |
102 |
103 | Basics
104 |
105 | How to style the UI elements themselves.
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | Layouts
119 |
120 | How to arrange the UI elements between each other.
121 |
122 |
123 | Position and z-index
124 | Overflowing content
125 | The Flex layout
126 | The Grid layout
127 | The Table layout
128 | Media queries
129 |
130 |
131 |
132 |
133 | Advanced CSS
134 |
135 |
136 | Although this part will use some Javascript, no previous knowledge of frameworks such as
137 | React is required.
138 |
139 |
140 |
141 | Animations
142 | CSS-in-JS
143 | Best practices and Stylelint
144 | How to choose your CSS tooling
145 | How to refactor legacy CSS
146 |
147 |
148 |
149 |
156 | >
157 | );
158 | };
159 |
160 | export default Home;
161 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: [
3 | 'eslint:recommended',
4 | 'plugin:prettier/recommended',
5 | 'plugin:import/recommended',
6 | 'next/core-web-vitals',
7 | ],
8 | env: {
9 | browser: true,
10 | es6: true,
11 | node: true,
12 | },
13 | globals: {
14 | alert: true,
15 | document: true,
16 | localStorage: true,
17 | navigator: true,
18 | window: true,
19 | HTMLElement: true,
20 | },
21 | ignorePatterns: [
22 | 'src/api/v1/gen/*',
23 | 'src/api/v2/gen/*',
24 | '**/*.svg',
25 | '**/*.scss',
26 | '**/*.md',
27 | '**/*.jpg',
28 | '**/*.png',
29 | ],
30 | overrides: [
31 | {
32 | files: ['*.ts', '*.tsx'],
33 | parser: '@typescript-eslint/parser',
34 | parserOptions: {
35 | project: 'tsconfig.json',
36 | },
37 | extends: [
38 | 'plugin:react/recommended',
39 | 'plugin:prettier/recommended',
40 | 'plugin:jsx-a11y/recommended',
41 | 'plugin:import/recommended',
42 | 'plugin:import/typescript',
43 | 'eslint:recommended',
44 | 'next/core-web-vitals',
45 | 'plugin:@typescript-eslint/recommended',
46 | 'plugin:@typescript-eslint/recommended-requiring-type-checking',
47 | 'plugin:prettier/recommended',
48 | ],
49 | plugins: ['jsx-a11y', 'prettier', 'react', '@typescript-eslint', 'react-hooks'],
50 |
51 | rules: {
52 | 'react-hooks/rules-of-hooks': 'error',
53 | 'react-hooks/exhaustive-deps': 'warn',
54 | 'prettier/prettier': 'error',
55 | 'import/extensions': 0,
56 | 'import/no-extraneous-dependencies': [
57 | 'error',
58 | {
59 | devDependencies: true,
60 | optionalDependencies: false,
61 | peerDependencies: false,
62 | },
63 | ],
64 | 'import/no-unresolved': 0,
65 | 'import/prefer-default-export': 0,
66 | 'react/jsx-filename-extension': [
67 | 'error',
68 | {
69 | extensions: ['.ts', '.tsx'],
70 | },
71 | ],
72 | 'react/no-array-index-key': 2,
73 | 'react/prop-types': 0,
74 | 'react/require-default-props': 0,
75 | 'react/jsx-curly-brace-presence': [
76 | 'error',
77 | {
78 | props: 'never',
79 | children: 'never',
80 | },
81 | ],
82 | '@typescript-eslint/explicit-function-return-type': 'off',
83 | '@typescript-eslint/explicit-member-accessibility': 0,
84 | '@typescript-eslint/camelcase': 0,
85 | '@typescript-eslint/interface-name-prefix': 0,
86 | 'no-unused-vars': 'off',
87 | '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
88 | 'react/react-in-jsx-scope': 'off',
89 | complexity: ['error', 8],
90 | 'max-lines': 'off',
91 | 'max-depth': ['error', 3],
92 | 'max-params': ['error', 5],
93 | 'arrow-body-style': ['error', 'as-needed'],
94 | '@typescript-eslint/no-explicit-any': 'error',
95 | '@typescript-eslint/no-non-null-assertion': 0,
96 | '@typescript-eslint/no-unnecessary-type-arguments': 'error',
97 | '@typescript-eslint/no-unnecessary-type-assertion': 'error',
98 | '@typescript-eslint/no-extra-non-null-assertion': 'error',
99 | '@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
100 | '@typescript-eslint/explicit-module-boundary-types': 'off',
101 | curly: ['error', 'all'],
102 | 'no-return-await': 'error',
103 | 'no-unused-expressions': [
104 | 'error',
105 | {
106 | allowShortCircuit: true,
107 | },
108 | ],
109 | eqeqeq: ['error', 'smart'],
110 | 'padding-line-between-statements': [
111 | 'error',
112 | {
113 | blankLine: 'always',
114 | prev: '*',
115 | next: 'return',
116 | },
117 | ],
118 | 'no-implicit-coercion': 'error',
119 | 'no-restricted-globals': 'error',
120 | 'no-case-declarations': 'error',
121 | '@typescript-eslint/prefer-regexp-exec': 'error',
122 | '@typescript-eslint/require-await': 'error',
123 | '@typescript-eslint/unbound-method': 'error',
124 | '@typescript-eslint/no-unsafe-assignment': 'error',
125 | '@typescript-eslint/no-unsafe-call': 'error',
126 | '@typescript-eslint/no-unsafe-return': 'error',
127 | '@typescript-eslint/no-unsafe-member-access': 'error',
128 | '@typescript-eslint/restrict-template-expressions': 'error',
129 | '@typescript-eslint/no-floating-promises': 'error',
130 | 'no-shadow': [
131 | 'error',
132 | {
133 | hoist: 'all',
134 | },
135 | ],
136 | 'prefer-const': 'warn',
137 | 'import/order': [
138 | 'error',
139 | {
140 | groups: [['external', 'builtin'], 'internal', ['parent', 'sibling', 'index']],
141 | },
142 | ],
143 | 'sort-imports': [
144 | 'error',
145 | {
146 | ignoreCase: true,
147 | ignoreDeclarationSort: true,
148 | ignoreMemberSort: false,
149 | memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
150 | },
151 | ],
152 | '@typescript-eslint/prefer-optional-chain': 'error',
153 | '@typescript-eslint/prefer-nullish-coalescing': 'error',
154 | '@typescript-eslint/strict-boolean-expressions': ['error', { allowNullableBoolean: true }],
155 | 'react/no-string-refs': 'error',
156 | },
157 | },
158 | ],
159 | settings: {
160 | react: {
161 | version: 'detect',
162 | },
163 | },
164 | root: true,
165 | };
166 |
--------------------------------------------------------------------------------
/services/skills.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 | import { Code } from 'components/Code';
3 | import { Image } from 'components/Image';
4 | import { PAGES } from './pages';
5 | import cssRuleQuestion from './css-rule-question.png';
6 |
7 | export interface Skill {
8 | skill: ReactNode;
9 | kataUrl: string;
10 | additionalInfos?: ReactNode;
11 | }
12 |
13 | export const SKILLS = {
14 | 'introduction-css-browser-rendering-vocabulary': {
15 | skill: 'What are the vocabulary words used to describe CSS code?',
16 | kataUrl: PAGES.WhyCSSHowItWorks.url() + '#definitions',
17 | additionalInfos: (
18 | <>
19 |
20 | >
21 | ),
22 | },
23 | 'introduction-css-browser-rendering-include': {
24 | skill: 'What are the 3 ways to include CSS in a page? What is the one you should not use?',
25 | kataUrl: PAGES.WhyCSSHowItWorks.url() + '#where-to-write-css',
26 | },
27 | 'introduction-css-browser-rendering-crp': {
28 | skill: (
29 | <>
30 | What is the Critical Rendering Path ?
31 | >
32 | ),
33 | kataUrl: PAGES.WhyCSSHowItWorks.url() + '#how-the-browser-renders-the-page',
34 | },
35 | 'introduction-css-browser-rendering-loading': {
36 | skill: 'How can CSS impact the load time of a page?',
37 | kataUrl: PAGES.WhyCSSHowItWorks.url() + '#how-the-browser-renders-the-page',
38 | },
39 | 'introduction-css-browser-rendering-feature': {
40 | skill: 'How can I check if a CSS feature is supported by a browser?',
41 | kataUrl: PAGES.WhyCSSHowItWorks.url() + '#invalid-css',
42 | },
43 | 'selectors-specificity-main': {
44 | skill: 'What are the main CSS selectors? (give at least 20 of them)',
45 | kataUrl: PAGES.SelectorsSpecificity.url() + '#base-selectors',
46 | },
47 | 'selectors-specificity-specificity': {
48 | skill: 'What is Specificity?',
49 | kataUrl: PAGES.SelectorsSpecificity.url() + '#specificity',
50 | },
51 | 'selectors-specificity-good-practices': {
52 | skill: 'What makes a good/bad CSS selector?',
53 | kataUrl: PAGES.SelectorsSpecificity.url() + '#what-makes-a-good-selector',
54 | },
55 | 'css-units-variables-units': {
56 | skill: 'What are the main CSS units and their definition? (give at least 7 of them)',
57 | kataUrl: PAGES.CSSUnitsVariables.url() + '#css-units',
58 | },
59 | 'css-units-variables-good-unit': {
60 | skill: 'When should I use relative or absolute units?',
61 | kataUrl: PAGES.SelectorsSpecificity.url() + '#css-units',
62 | },
63 | 'css-units-variables-px-rem': {
64 | skill: 'Should I use px or rem/em?',
65 | kataUrl: PAGES.SelectorsSpecificity.url() + '#css-units',
66 | },
67 | 'css-units-variables-variables': {
68 | skill: 'How can I use CSS variables?',
69 | kataUrl: PAGES.SelectorsSpecificity.url() + '#css-variables',
70 | },
71 | 'css-units-variables-keywords': {
72 | skill: (
73 | <>
74 | What are the differences between inherit, initial and{' '}
75 | unset?
76 | >
77 | ),
78 | kataUrl: PAGES.SelectorsSpecificity.url() + '#css-cascade',
79 | },
80 | 'styling-text-custom-fonts-standard-font-size': {
81 | skill: 'What are the properties to change the style of a text? (give at least 5 of them)',
82 | kataUrl: PAGES.StylingTextCustomFonts.url() + '#basic-text-styling',
83 | },
84 | 'styling-text-custom-fonts-include-fonts': {
85 | skill: 'How can I include custom fonts?',
86 | kataUrl: PAGES.StylingTextCustomFonts.url() + '#font-families-custom-fonts',
87 | },
88 | 'styling-text-custom-fonts': {
89 | skill: 'What are the 3 steps of font loading?',
90 | kataUrl: PAGES.StylingTextCustomFonts.url() + '#font-families-custom-fonts',
91 | },
92 | 'styling-text-custom-fonts-variable-fonts': {
93 | skill: 'What is a variable font?',
94 | kataUrl: PAGES.StylingTextCustomFonts.url() + '#variable-fonts',
95 | },
96 | 'box-model-definition': {
97 | skill: 'What is the box model?',
98 | kataUrl: PAGES.TheBoxModel.url() + '#definition',
99 | },
100 | 'box-model-alternatives': {
101 | skill: 'What are the two possible box models?',
102 | kataUrl: PAGES.TheBoxModel.url() + '#box-sizing-property',
103 | },
104 | 'box-model-layout': {
105 | skill: 'In CSS, what is a layout?',
106 | kataUrl: PAGES.TheBoxModel.url() + '#layouts',
107 | },
108 | 'box-model-common-layouts': {
109 | skill: 'What are the most common layouts?',
110 | kataUrl: PAGES.TheBoxModel.url() + '#layouts',
111 | },
112 | 'box-model-outer-inner-display': {
113 | skill: 'What are the outer and inner display types?',
114 | kataUrl: PAGES.TheBoxModel.url() + '#display',
115 | },
116 | 'flow-layout-block-formatting-context': {
117 | skill: 'What is a Block Formatting Context?',
118 | kataUrl: PAGES.FlowLayout.url() + '#block-formatting-context',
119 | },
120 | 'flow-layout-boxes': {
121 | skill: 'How inline and block boxes are laid out in the Flow layout?',
122 | kataUrl: PAGES.FlowLayout.url() + '#inline-block-boxes-grouping',
123 | },
124 | 'flow-layout-block-formatting': {
125 | skill: 'What are the rules of block formatting?',
126 | kataUrl: PAGES.FlowLayout.url() + '#block-formatting',
127 | },
128 | 'flow-layout-margin-collapsing': {
129 | skill: 'How does margin collapsing work?',
130 | kataUrl: PAGES.FlowLayout.url() + '#block-formatting',
131 | },
132 | 'flow-layout-inline-formatting': {
133 | skill: 'What are the rules of inline formatting?',
134 | kataUrl: PAGES.FlowLayout.url() + '#inline-formatting',
135 | },
136 | } satisfies { [key: string]: Skill };
137 |
138 | interface SkillWithId extends Skill {
139 | id: keyof typeof SKILLS;
140 | }
141 |
142 | export const SKILLS_LIST: SkillWithId[] = Object.entries(SKILLS).map(
143 | ([id, skill]): SkillWithId => ({
144 | id: id as keyof typeof SKILLS,
145 | ...skill,
146 | }),
147 | );
148 |
--------------------------------------------------------------------------------
/app/(main)/learn/basics/the-box-model-and-layouts/box-model.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
17 | Content margin padding border height Width
--------------------------------------------------------------------------------
/app/(main)/learn/basics/the-box-model-and-layouts/border-box-model.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
17 | Content margin padding border Width height
18 |
--------------------------------------------------------------------------------
/app/(main)/learn/basics/introduction-css-how-the-browser-renders-the-page/page.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from 'next';
2 | import { Subsubtitle, Subtitle, Title } from 'components/Layout';
3 | import { Exercise } from 'components/Exercise';
4 | import { Image } from 'components/Image';
5 | import { Code } from 'components/Code';
6 | import { NextKataButton } from 'components/NextKataButton';
7 | import { KataQuestions } from 'components/KataQuestions';
8 | import { Link } from 'components/Link';
9 | import { Divider } from 'components/Divider';
10 | import { PAGES } from 'services/pages';
11 | import { Editor } from 'components/Editor';
12 | import { KataRating } from 'components/KataRating';
13 | import CssRuleImage from './css-rule.svg';
14 | import RenderProcessImage from './render-process.svg';
15 | import profilerImage from './profiler.png';
16 |
17 | const Kata: NextPage = () => (
18 | <>
19 | {PAGES.WhyCSSHowItWorks.title}
20 |
21 |
22 |
23 | Welcome to cssdojo! This is the first{' '}
24 |
30 | kata
31 |
32 | , so let me tell you how it works.
33 |
34 |
35 | Each kata begins with a list of questions that will be addressed by the kata.
36 |
37 | You can check the boxes to keep track of your progress and they will be saved on this
38 | browser.{' '}
39 |
40 | Check the box only if you feel you can explain clearly the answer to another person.
41 | {' '}
42 | You will also find them in{' '}
43 | the complete list of questions.
44 |
45 |
46 |
47 | There will be live code editors embedded in the page: play with them as
48 | long as you want!
49 |
50 |
51 |
52 | At the end, there will be a short recap with the most important things to
53 | remember. You can always go back to this kata later and check the questions/recap again.
54 |
55 |
56 | With that being said, let’s (re)learn CSS!
57 |
58 |
59 |
60 |
61 |
70 |
71 |
72 | Definitions
73 |
74 | CSS stands for Cascading Style Sheets . It is a core web language, with HTML
75 | and JS it forms the base for website creation. HTML conveys the meaning of the document,
76 | Javascript can change it dynamically and CSS is for improving the looks of it.
77 |
78 |
79 | Some vocabulary first. When we write CSS, we write a lot of CSS rules:
80 |
81 | }
83 | alt=""
84 | caption="An example of CSS rule: make all the first-level titles red and big"
85 | style={{ maxWidth: '20rem' }}
86 | />
87 |
88 |
89 |
90 | Rule
91 |
92 | A selector followed by multiple declarations inside curly braces
93 |
94 |
95 | Selector
96 |
97 |
98 | Points to the HTML element(s) that you want to style (in the case above: h1)
99 |
100 |
101 |
102 | Declaration
103 |
104 |
105 | A combination of a CSS property and a value (in the case
106 | above: color: red;)
107 |
108 |
109 |
110 |
111 | We’re going to learn a lot of selectors, properties and values in the next katas. But first,{' '}
112 |
113 | it is important to understand where to write CSS and how the browser renders it.
114 |
115 |
116 |
117 |
118 |
119 | Where do we write CSS?
120 |
121 | There are 3 ways to include CSS in a HTML page:
122 |
123 |
124 |
125 | In a <style> HTML tag inside the HTML <head>
126 |
127 |
128 | In an external file linked by inserting a <link> HTML tag inside the
129 | HTML <head>
130 |
131 |
132 | Inside the style attribute of any HTML tag
133 |
134 |
135 |
136 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
147 |
148 |
149 |
150 | Hello world!
151 |
152 |
153 | This is some text.
154 |
155 |
156 | This is important.
157 |
158 |
159 |
160 |