CSS Nesting to natywna funkcjonalność CSS, która pozwala na zagnieżdżanie selektorów wewnątrz innych selektorów, podobnie jak w preprocesorach takich jak Sass czy Less. To znacząco poprawia czytelność i organizację kodu CSS.
1/* Tradycyjny CSS */
2.card {
3 padding: 1rem;
4 background: white;
5 border-radius: 8px;
6}
7
8.card h2 {
9 font-size: 1.5rem;
10 margin-bottom: 1rem;
11 color: #333;
12}
13
14.card p {
15 line-height: 1.6;
16 color: #666;
17}
18
19.card .button {
20 padding: 0.5rem 1rem;
21 background: #007bff;
22 color: white;
23 border: none;
24 border-radius: 4px;
25}
26
27/* CSS Nesting */
28.card {
29 padding: 1rem;
30 background: white;
31 border-radius: 8px;
32
33 h2 {
34 font-size: 1.5rem;
35 margin-bottom: 1rem;
36 color: #333;
37 }
38
39 p {
40 line-height: 1.6;
41 color: #666;
42 }
43
44 .button {
45 padding: 0.5rem 1rem;
46 background: #007bff;
47 color: white;
48 border: none;
49 border-radius: 4px;
50 }
51}Symbol
& reprezentuje selektor rodzica i pozwala na tworzenie bardziej złożonych selektorów:1.button {
2 padding: 0.75rem 1.5rem;
3 background: #007bff;
4 color: white;
5 border: none;
6 border-radius: 4px;
7 cursor: pointer;
8 transition: all 0.3s ease;
9
10 /* Stany hover i focus */
11 &:hover {
12 background: #0056b3;
13 transform: translateY(-1px);
14 }
15
16 &:focus {
17 outline: none;
18 box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
19 }
20
21 &:active {
22 transform: translateY(0);
23 }
24
25 /* Warianty przycisków */
26 &.secondary {
27 background: #6c757d;
28
29 &:hover {
30 background: #545b62;
31 }
32 }
33
34 &.danger {
35 background: #dc3545;
36
37 &:hover {
38 background: #c82333;
39 }
40 }
41
42 /* Modyfikatory stanu */
43 &.loading {
44 position: relative;
45 color: transparent;
46
47 &::after {
48 content: '';
49 position: absolute;
50 top: 50%;
51 left: 50%;
52 width: 16px;
53 height: 16px;
54 border: 2px solid #ffffff;
55 border-top: 2px solid transparent;
56 border-radius: 50%;
57 animation: spin 1s linear infinite;
58 transform: translate(-50%, -50%);
59 }
60 }
61
62 &:disabled {
63 opacity: 0.6;
64 cursor: not-allowed;
65
66 &:hover {
67 background: #007bff;
68 transform: none;
69 }
70 }
71}
72
73@keyframes spin {
74 0% { transform: translate(-50%, -50%) rotate(0deg); }
75 100% { transform: translate(-50%, -50%) rotate(360deg); }
76}1.navigation {
2 display: flex;
3 align-items: center;
4 padding: 1rem 2rem;
5 background: #ffffff;
6 box-shadow: 0 2px 4px rgba(0,0,0,0.1);
7
8 .logo {
9 font-size: 1.5rem;
10 font-weight: bold;
11 color: #007bff;
12 text-decoration: none;
13
14 &:hover {
15 color: #0056b3;
16 }
17 }
18
19 .nav-list {
20 display: flex;
21 list-style: none;
22 margin: 0 0 0 auto;
23 padding: 0;
24 gap: 2rem;
25
26 .nav-item {
27 position: relative;
28
29 .nav-link {
30 display: block;
31 padding: 0.5rem 0;
32 color: #333;
33 text-decoration: none;
34 font-weight: 500;
35 transition: color 0.3s ease;
36
37 &:hover {
38 color: #007bff;
39 }
40
41 &.active {
42 color: #007bff;
43
44 &::after {
45 content: '';
46 position: absolute;
47 bottom: -8px;
48 left: 0;
49 right: 0;
50 height: 2px;
51 background: #007bff;
52 }
53 }
54 }
55
56 /* Dropdown menu */
57 .dropdown {
58 position: absolute;
59 top: 100%;
60 left: 0;
61 min-width: 200px;
62 background: white;
63 border-radius: 8px;
64 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
65 opacity: 0;
66 visibility: hidden;
67 transform: translateY(-10px);
68 transition: all 0.3s ease;
69 z-index: 1000;
70
71 .dropdown-item {
72 .dropdown-link {
73 display: block;
74 padding: 0.75rem 1rem;
75 color: #333;
76 text-decoration: none;
77
78 &:hover {
79 background: #f8f9fa;
80 color: #007bff;
81 }
82
83 &:first-child {
84 border-radius: 8px 8px 0 0;
85 }
86
87 &:last-child {
88 border-radius: 0 0 8px 8px;
89 }
90 }
91 }
92 }
93
94 /* Pokaż dropdown przy hover */
95 &:hover .dropdown {
96 opacity: 1;
97 visibility: visible;
98 transform: translateY(0);
99 }
100 }
101 }
102
103 /* Responsive navigation */
104 .mobile-toggle {
105 display: none;
106 flex-direction: column;
107 gap: 4px;
108 background: none;
109 border: none;
110 cursor: pointer;
111
112 .bar {
113 width: 25px;
114 height: 3px;
115 background: #333;
116 transition: all 0.3s ease;
117 }
118
119 &.active {
120 .bar:nth-child(1) {
121 transform: rotate(45deg) translate(5px, 5px);
122 }
123
124 .bar:nth-child(2) {
125 opacity: 0;
126 }
127
128 .bar:nth-child(3) {
129 transform: rotate(-45deg) translate(7px, -6px);
130 }
131 }
132 }
133
134 @media (max-width: 768px) {
135 .nav-list {
136 position: fixed;
137 top: 70px;
138 left: 0;
139 right: 0;
140 flex-direction: column;
141 background: white;
142 padding: 1rem 2rem;
143 transform: translateY(-100%);
144 transition: transform 0.3s ease;
145 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
146
147 &.active {
148 transform: translateY(0);
149 }
150
151 .nav-item {
152 .dropdown {
153 position: static;
154 opacity: 1;
155 visibility: visible;
156 transform: none;
157 box-shadow: none;
158 background: #f8f9fa;
159 margin-top: 0.5rem;
160 }
161 }
162 }
163
164 .mobile-toggle {
165 display: flex;
166 }
167 }
168}1.hero-section {
2 display: flex;
3 align-items: center;
4 min-height: 100vh;
5 padding: 2rem;
6 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
7 color: white;
8
9 .hero-content {
10 max-width: 1200px;
11 margin: 0 auto;
12 text-align: center;
13
14 .hero-title {
15 font-size: 3.5rem;
16 font-weight: 700;
17 margin-bottom: 1.5rem;
18 line-height: 1.2;
19
20 @media (max-width: 768px) {
21 font-size: 2.5rem;
22 }
23
24 @media (max-width: 480px) {
25 font-size: 2rem;
26 }
27 }
28
29 .hero-subtitle {
30 font-size: 1.5rem;
31 font-weight: 300;
32 margin-bottom: 2rem;
33 opacity: 0.9;
34
35 @media (max-width: 768px) {
36 font-size: 1.25rem;
37 }
38
39 @media (max-width: 480px) {
40 font-size: 1.1rem;
41 }
42 }
43
44 .hero-buttons {
45 display: flex;
46 gap: 1rem;
47 justify-content: center;
48 flex-wrap: wrap;
49
50 @media (max-width: 480px) {
51 flex-direction: column;
52 align-items: center;
53 }
54
55 .btn-primary {
56 padding: 1rem 2rem;
57 font-size: 1.1rem;
58 background: rgba(255, 255, 255, 0.2);
59 border: 2px solid white;
60 color: white;
61 border-radius: 50px;
62 text-decoration: none;
63 transition: all 0.3s ease;
64 backdrop-filter: blur(10px);
65
66 &:hover {
67 background: white;
68 color: #667eea;
69 transform: translateY(-2px);
70 box-shadow: 0 8px 25px rgba(0,0,0,0.2);
71 }
72
73 @media (max-width: 480px) {
74 width: 200px;
75 }
76 }
77
78 .btn-secondary {
79 padding: 1rem 2rem;
80 font-size: 1.1rem;
81 background: transparent;
82 border: 2px solid rgba(255, 255, 255, 0.5);
83 color: white;
84 border-radius: 50px;
85 text-decoration: none;
86 transition: all 0.3s ease;
87
88 &:hover {
89 border-color: white;
90 background: rgba(255, 255, 255, 0.1);
91 }
92
93 @media (max-width: 480px) {
94 width: 200px;
95 }
96 }
97 }
98 }
99
100 @media (max-width: 768px) {
101 padding: 1rem;
102 min-height: 80vh;
103 }
104}1.contact-form {
2 max-width: 600px;
3 margin: 2rem auto;
4 padding: 2rem;
5 background: white;
6 border-radius: 12px;
7 box-shadow: 0 8px 25px rgba(0,0,0,0.1);
8
9 .form-header {
10 text-align: center;
11 margin-bottom: 2rem;
12
13 h2 {
14 font-size: 2rem;
15 color: #333;
16 margin-bottom: 0.5rem;
17 }
18
19 p {
20 color: #666;
21 font-size: 1.1rem;
22 }
23 }
24
25 .form-row {
26 display: flex;
27 gap: 1rem;
28 margin-bottom: 1.5rem;
29
30 @media (max-width: 600px) {
31 flex-direction: column;
32 }
33
34 .form-group {
35 flex: 1;
36
37 &.full-width {
38 flex-basis: 100%;
39 }
40 }
41 }
42
43 .form-group {
44 margin-bottom: 1.5rem;
45
46 label {
47 display: block;
48 margin-bottom: 0.5rem;
49 font-weight: 600;
50 color: #333;
51
52 .required {
53 color: #e74c3c;
54 margin-left: 0.25rem;
55 }
56 }
57
58 input, textarea, select {
59 width: 100%;
60 padding: 0.75rem;
61 border: 2px solid #e1e5e9;
62 border-radius: 8px;
63 font-size: 1rem;
64 transition: all 0.3s ease;
65 background: #fafbfc;
66
67 &:focus {
68 outline: none;
69 border-color: #007bff;
70 background: white;
71 box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
72 }
73
74 &::placeholder {
75 color: #adb5bd;
76 }
77
78 &.error {
79 border-color: #e74c3c;
80 background: #fff5f5;
81
82 &:focus {
83 box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.1);
84 }
85 }
86
87 &.success {
88 border-color: #28a745;
89 background: #f8fff9;
90
91 &:focus {
92 box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.1);
93 }
94 }
95 }
96
97 textarea {
98 min-height: 120px;
99 resize: vertical;
100 }
101
102 select {
103 cursor: pointer;
104 background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
105 background-position: right 0.5rem center;
106 background-repeat: no-repeat;
107 background-size: 1.5em 1.5em;
108 padding-right: 2.5rem;
109 }
110
111 .error-message {
112 display: block;
113 margin-top: 0.5rem;
114 color: #e74c3c;
115 font-size: 0.875rem;
116 }
117
118 .help-text {
119 display: block;
120 margin-top: 0.5rem;
121 color: #6c757d;
122 font-size: 0.875rem;
123 }
124 }
125
126 .checkbox-group {
127 margin: 1.5rem 0;
128
129 .checkbox-item {
130 display: flex;
131 align-items: center;
132 gap: 0.75rem;
133 margin-bottom: 1rem;
134
135 input[type="checkbox"] {
136 width: auto;
137 margin: 0;
138
139 &:checked + label::before {
140 background-color: #007bff;
141 border-color: #007bff;
142 }
143 }
144
145 label {
146 margin: 0;
147 cursor: pointer;
148 user-select: none;
149
150 a {
151 color: #007bff;
152 text-decoration: none;
153
154 &:hover {
155 text-decoration: underline;
156 }
157 }
158 }
159 }
160 }
161
162 .form-actions {
163 display: flex;
164 gap: 1rem;
165 justify-content: flex-end;
166 margin-top: 2rem;
167
168 @media (max-width: 480px) {
169 flex-direction: column;
170 }
171
172 .btn {
173 padding: 0.75rem 2rem;
174 border: none;
175 border-radius: 8px;
176 font-size: 1rem;
177 font-weight: 600;
178 cursor: pointer;
179 transition: all 0.3s ease;
180 text-decoration: none;
181 display: inline-block;
182 text-align: center;
183
184 &.btn-primary {
185 background: #007bff;
186 color: white;
187
188 &:hover:not(:disabled) {
189 background: #0056b3;
190 transform: translateY(-1px);
191 }
192
193 &:disabled {
194 opacity: 0.6;
195 cursor: not-allowed;
196 }
197 }
198
199 &.btn-secondary {
200 background: #f8f9fa;
201 color: #6c757d;
202 border: 1px solid #dee2e6;
203
204 &:hover {
205 background: #e9ecef;
206 color: #495057;
207 }
208 }
209
210 @media (max-width: 480px) {
211 width: 100%;
212 }
213 }
214 }
215
216 .loading-overlay {
217 position: absolute;
218 top: 0;
219 left: 0;
220 right: 0;
221 bottom: 0;
222 background: rgba(255, 255, 255, 0.9);
223 display: flex;
224 align-items: center;
225 justify-content: center;
226 border-radius: 12px;
227
228 .spinner {
229 width: 40px;
230 height: 40px;
231 border: 4px solid #f3f3f3;
232 border-top: 4px solid #007bff;
233 border-radius: 50%;
234 animation: spin 1s linear infinite;
235 }
236 }
237}1.card {
2 background: white;
3 border-radius: 12px;
4 overflow: hidden;
5 transition: all 0.3s ease;
6 position: relative;
7
8 /* Warianty cieni */
9 &.shadow-sm {
10 box-shadow: 0 1px 3px rgba(0,0,0,0.1);
11 }
12
13 &.shadow-md {
14 box-shadow: 0 4px 6px rgba(0,0,0,0.1);
15 }
16
17 &.shadow-lg {
18 box-shadow: 0 10px 25px rgba(0,0,0,0.15);
19 }
20
21 /* Warianty interaktywne */
22 &.hoverable {
23 cursor: pointer;
24
25 &:hover {
26 transform: translateY(-4px);
27 box-shadow: 0 12px 30px rgba(0,0,0,0.2);
28 }
29 }
30
31 &.clickable {
32 cursor: pointer;
33 user-select: none;
34
35 &:active {
36 transform: scale(0.98);
37 }
38 }
39
40 /* Komponenty karty */
41 .card-header {
42 padding: 1.5rem;
43 border-bottom: 1px solid #f0f0f0;
44
45 &.with-image {
46 padding: 0;
47 position: relative;
48
49 .header-image {
50 width: 100%;
51 height: 200px;
52 object-fit: cover;
53 }
54
55 .header-content {
56 position: absolute;
57 bottom: 0;
58 left: 0;
59 right: 0;
60 padding: 1.5rem;
61 background: linear-gradient(transparent, rgba(0,0,0,0.7));
62 color: white;
63 }
64 }
65
66 .card-title {
67 font-size: 1.5rem;
68 font-weight: 600;
69 margin: 0 0 0.5rem 0;
70 color: #333;
71
72 .card-header.with-image & {
73 color: white;
74 }
75 }
76
77 .card-subtitle {
78 font-size: 1rem;
79 color: #666;
80 margin: 0;
81
82 .card-header.with-image & {
83 color: rgba(255,255,255,0.9);
84 }
85 }
86 }
87
88 .card-body {
89 padding: 1.5rem;
90
91 .card-text {
92 line-height: 1.6;
93 color: #555;
94 margin-bottom: 1rem;
95
96 &:last-child {
97 margin-bottom: 0;
98 }
99 }
100
101 .card-meta {
102 display: flex;
103 align-items: center;
104 gap: 1rem;
105 margin-bottom: 1rem;
106 font-size: 0.9rem;
107 color: #666;
108
109 .meta-item {
110 display: flex;
111 align-items: center;
112 gap: 0.25rem;
113
114 .icon {
115 width: 16px;
116 height: 16px;
117 }
118 }
119 }
120
121 .card-tags {
122 display: flex;
123 flex-wrap: wrap;
124 gap: 0.5rem;
125 margin-bottom: 1rem;
126
127 .tag {
128 padding: 0.25rem 0.75rem;
129 background: #f8f9fa;
130 color: #495057;
131 border-radius: 20px;
132 font-size: 0.8rem;
133 font-weight: 500;
134
135 &.primary {
136 background: #e3f2fd;
137 color: #1976d2;
138 }
139
140 &.success {
141 background: #e8f5e8;
142 color: #2e7d32;
143 }
144
145 &.warning {
146 background: #fff3e0;
147 color: #f57c00;
148 }
149
150 &.danger {
151 background: #ffebee;
152 color: #d32f2f;
153 }
154 }
155 }
156 }
157
158 .card-footer {
159 padding: 1rem 1.5rem;
160 background: #f8f9fa;
161 border-top: 1px solid #f0f0f0;
162
163 .card-actions {
164 display: flex;
165 justify-content: space-between;
166 align-items: center;
167 gap: 1rem;
168
169 @media (max-width: 480px) {
170 flex-direction: column;
171 align-items: stretch;
172 }
173
174 .action-group {
175 display: flex;
176 gap: 0.5rem;
177
178 @media (max-width: 480px) {
179 justify-content: center;
180 }
181 }
182
183 .btn {
184 padding: 0.5rem 1rem;
185 border: none;
186 border-radius: 6px;
187 font-size: 0.9rem;
188 cursor: pointer;
189 text-decoration: none;
190 transition: all 0.2s ease;
191
192 &.btn-primary {
193 background: #007bff;
194 color: white;
195
196 &:hover {
197 background: #0056b3;
198 }
199 }
200
201 &.btn-outline {
202 background: transparent;
203 color: #007bff;
204 border: 1px solid #007bff;
205
206 &:hover {
207 background: #007bff;
208 color: white;
209 }
210 }
211
212 &.btn-ghost {
213 background: transparent;
214 color: #6c757d;
215
216 &:hover {
217 background: #e9ecef;
218 color: #495057;
219 }
220 }
221 }
222 }
223 }
224
225 /* Stany specjalne */
226 &.loading {
227 pointer-events: none;
228
229 &::after {
230 content: '';
231 position: absolute;
232 top: 0;
233 left: 0;
234 right: 0;
235 bottom: 0;
236 background: rgba(255,255,255,0.8);
237 display: flex;
238 align-items: center;
239 justify-content: center;
240 }
241 }
242
243 &.disabled {
244 opacity: 0.6;
245 pointer-events: none;
246 }
247}1/* ✅ Dobrze - maksymalnie 3-4 poziomy */
2.header {
3 .navigation {
4 .nav-item {
5 .nav-link {
6 /* maksymalny poziom */
7 }
8 }
9 }
10}
11
12/* ❌ Źle - zbyt głębokie zagnieżdżenie */
13.page {
14 .content {
15 .section {
16 .container {
17 .row {
18 .column {
19 .card {
20 .header {
21 /* zbyt głęboko! */
22 }
23 }
24 }
25 }
26 }
27 }
28 }
29}1/* ✅ Dobrze */
2.product-card {
3 .product-image {
4 /* style */
5 }
6
7 .product-info {
8 .product-title { /* style */ }
9 .product-price { /* style */ }
10 }
11}
12
13/* ❌ Źle */
14.card {
15 .img {
16 /* style */
17 }
18
19 .info {
20 .title { /* style */ }
21 .price { /* style */ }
22 }
23}1.modal {
2 /* Podstawowe style layoutu */
3 position: fixed;
4 top: 0;
5 left: 0;
6 width: 100%;
7 height: 100%;
8 z-index: 1000;
9
10 /* Tło i overlay */
11 .modal-backdrop {
12 position: absolute;
13 top: 0;
14 left: 0;
15 width: 100%;
16 height: 100%;
17 background: rgba(0,0,0,0.5);
18 backdrop-filter: blur(4px);
19 }
20
21 /* Zawartość modala */
22 .modal-content {
23 position: relative;
24 max-width: 500px;
25 margin: 5% auto;
26 background: white;
27 border-radius: 12px;
28 overflow: hidden;
29
30 /* Komponenty modala */
31 .modal-header {
32 /* style */
33 }
34
35 .modal-body {
36 /* style */
37 }
38
39 .modal-footer {
40 /* style */
41 }
42 }
43
44 /* Stany i animacje */
45 &.fade-in {
46 animation: modalFadeIn 0.3s ease;
47 }
48
49 &.fade-out {
50 animation: modalFadeOut 0.3s ease;
51 }
52}CSS Nesting znacząco poprawia organizację i czytelność kodu CSS, umożliwiając tworzenie bardziej intuicyjnych i łatwiejszych w utrzymaniu arkuszy stylów. Kluczem jest zachowanie umiaru i przestrzeganie dobrych praktyk.