Основы веб-разработки: HTML, CSS, JavaScript, манипуляция DOM и адаптивный дизайн
Этот материал представляет собой полное введение в основы веб-разработки с примерами HTML5, CSS3, JavaScript ES6+, манипуляцией DOM и адаптивным дизайном.
Суть
Веб-разработка опирается на три ключевых технологии: HTML для структуры, CSS для оформления и JavaScript для интерактивности. Адаптивный дизайн обеспечивает оптимальное отображение на всех устройствах.
Определение
Веб-разработка это создание веб-приложений путём сочетания языков разметки, стилей и программирования.
Ключевые технологии:
HTML5 (HyperText Markup Language)
- Структура: семантическая разметка содержимого
- Элементы: header, nav, main, section, article, footer
- Формы: типы input, валидация, доступность
- Мультимедиа: audio, video, canvas, SVG
CSS3 (Cascading Style Sheets)
- Стилизация: цвета, шрифты, макет, анимации
- Макет: flexbox, grid, позиционирование, адаптивный дизайн
- Псевдоклассы: :hover, :active, :focus, :nth-child
- Media queries: адаптивный дизайн, контрольные точки
JavaScript ES6+
- Интерактивность: манипуляция DOM, обработка событий
- Возможности: стрелочные функции, шаблонные строки, деструктуризация
- DOM API: выбор элементов, их изменение, события
- Асинхронность: promises, async/await, Fetch API
Ключевые моменты
- HTML5: семантический язык разметки для веб-контента
- CSS3: язык стилей для дизайна и макета
- JavaScript: язык программирования для веб-интерактивности
- DOM: Document Object Model для динамических изменений
- Адаптивный дизайн: адаптация под разные размеры экранов
- Media queries: CSS-условия для свойств устройств
- Flexbox/Grid: современные техники макета
- Основа: необходимы для всех профессий в веб-разработке
Основные компоненты
- HTML5: семантическая структура и содержимое
- CSS3: визуальное оформление и макет
- JavaScript: динамическая функциональность
- DOM: программный интерфейс
- Адаптивный дизайн: совместимость со всеми устройствами
- Доступность: разработка без барьеров
- Производительность: скорость загрузки и оптимизация
- Best practices: современные стандарты разработки
Практические примеры
1. Базовая структура HTML5
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Moderne Webanwendung mit HTML5, CSS3 und JavaScript">
<title>Webentwicklung Demo</title>
<!-- CSS einbinden -->
<link rel="stylesheet" href="styles.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap" rel="stylesheet">
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<!-- Open Graph Meta Tags -->
<meta property="og:title" content="Webentwicklung Demo">
<meta property="og:description" content="Moderne Webanwendung">
<meta property="og:type" content="website">
</head>
<body>
<!-- Skip Navigation für Accessibility -->
<a href="#main-content" class="skip-link">Zum Hauptinhalt springen</a>
<!-- Header mit Navigation -->
<header class="header">
<nav class="nav" aria-label="Hauptnavigation">
<div class="nav-container">
<div class="nav-brand">
<a href="#" class="brand-link">
<img src="logo.svg" alt="Logo" class="brand-logo">
<span class="brand-text">WebDev</span>
</a>
</div>
<button class="nav-toggle" aria-expanded="false" aria-controls="nav-menu">
<span class="hamburger"></span>
<span class="visually-hidden">Menü</span>
</button>
<ul id="nav-menu" class="nav-menu">
<li><a href="#home" class="nav-link">Home</a></li>
<li><a href="#features" class="nav-link">Features</a></li>
<li><a href="#contact" class="nav-link">Kontakt</a></li>
</ul>
</div>
</nav>
</header>
<!-- Hauptinhalt -->
<main id="main-content" class="main">
<!-- Hero Section -->
<section class="hero" id="home">
<div class="container">
<h1 class="hero-title">Moderne Webentwicklung</h1>
<p class="hero-subtitle">HTML5, CSS3 und JavaScript in Aktion</p>
<div class="hero-actions">
<button class="btn btn-primary" data-action="start">Starten</button>
<a href="#features" class="btn btn-secondary">Mehr erfahren</a>
</div>
<!-- Interactive Demo -->
<div class="demo-section">
<div class="demo-container">
<canvas id="demo-canvas" width="400" height="200"></canvas>
<div class="demo-controls">
<button class="demo-btn" data-action="clear">Löschen</button>
<button class="demo-btn" data-action="animate">Animieren</button>
<input type="color" id="color-picker" value="#3b82f6">
</div>
</div>
</div>
</div>
</section>
<!-- Features Section -->
<section class="features" id="features">
<div class="container">
<h2 class="section-title">Features</h2>
<div class="features-grid">
<article class="feature-card">
<div class="feature-icon">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2L2 7v10c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V7l-10-5z"/>
</svg>
</div>
<h3 class="feature-title">Sicherheit</h3>
<p class="feature-description">Moderne Sicherheitsstandards und Best Practices</p>
</article>
<article class="feature-card">
<div class="feature-icon">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
<line x1="8" y1="21" x2="16" y2="21"/>
<line x1="12" y1="17" x2="12" y2="21"/>
</svg>
</div>
<h3 class="feature-title">Responsive</h3>
<p class="feature-description">Optimale Darstellung auf allen Geräten</p>
</article>
<article class="feature-card">
<div class="feature-icon">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
</svg>
</div>
<h3 class="feature-title">Performance</h3>
<p class="feature-description">Schnelle Ladezeiten und reibungslose Interaktion</p>
</article>
</div>
</div>
</section>
<!-- Kontakt Formular -->
<section class="contact" id="contact">
<div class="container">
<h2 class="section-title">Kontakt</h2>
<form class="contact-form" novalidate>
<div class="form-group">
<label for="name" class="form-label">Name *</label>
<input type="text" id="name" name="name" class="form-input" required>
<span class="form-error" id="name-error">Bitte geben Sie Ihren Namen ein</span>
</div>
<div class="form-group">
<label for="email" class="form-label">E-Mail *</label>
<input type="email" id="email" name="email" class="form-input" required>
<span class="form-error" id="email-error">Bitte geben Sie eine gültige E-Mail ein</span>
</div>
<div class="form-group">
<label for="message" class="form-label">Nachricht</label>
<textarea id="message" name="message" class="form-textarea" rows="4"></textarea>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Senden</button>
<button type="reset" class="btn btn-secondary">Zurücksetzen</button>
</div>
</form>
</div>
</section>
</main>
<!-- Footer -->
<footer class="footer">
<div class="container">
<p>© 2024 Webentwicklung Demo. Alle Rechte vorbehalten.</p>
<div class="footer-links">
<a href="#impressum">Impressum</a>
<a href="#datenschutz">Datenschutz</a>
</div>
</div>
</footer>
<!-- JavaScript einbinden -->
<script src="script.js"></script>
</body>
</html>
2. CSS3 с Responsive Design
/* CSS Reset и базовые стили */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* CSS Custom Properties (переменные) */
:root {
/* Цвета */
--color-primary: #3b82f6;
--color-primary-dark: #2563eb;
--color-primary-light: #60a5fa;
--color-secondary: #64748b;
--color-success: #10b981;
--color-error: #ef4444;
--color-warning: #f59e0b;
/* Нейтральные */
--color-white: #ffffff;
--color-gray-50: #f8fafc;
--color-gray-100: #f1f5f9;
--color-gray-900: #0f172a;
/* Типография */
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
/* Отступы */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
--spacing-2xl: 3rem;
/* Радиус границ */
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
--radius-full: 9999px;
/* Тени */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
/* Переходы */
--transition-fast: 150ms ease-in-out;
--transition-normal: 300ms ease-in-out;
--transition-slow: 500ms ease-in-out;
}
/* Базовые стили */
html {
font-size: 16px;
scroll-behavior: smooth;
}
body {
font-family: var(--font-family);
font-size: var(--font-size-base);
line-height: 1.6;
color: var(--color-gray-900);
background-color: var(--color-white);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Утилиты */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 var(--spacing-md);
}
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: var(--color-primary);
color: var(--color-white);
padding: var(--spacing-sm) var(--spacing-md);
text-decoration: none;
border-radius: var(--radius-md);
z-index: 100;
transition: top var(--transition-fast);
}
.skip-link:focus {
top: var(--spacing-sm);
}
/* Шапка и навигация */
.header {
background-color: var(--color-white);
box-shadow: var(--shadow-sm);
position: sticky;
top: 0;
z-index: 50;
}
.nav-container {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--spacing-md) 0;
}
.brand-link {
display: flex;
align-items: center;
gap: var(--spacing-sm);
text-decoration: none;
color: var(--color-gray-900);
font-weight: 600;
transition: color var(--transition-fast);
}
.brand-link:hover {
color: var(--color-primary);
}
.brand-logo {
width: 32px;
height: 32px;
}
.nav-toggle {
display: none;
background: none;
border: none;
padding: var(--spacing-sm);
cursor: pointer;
}
.hamburger {
display: block;
width: 24px;
height: 2px;
background-color: var(--color-gray-900);
position: relative;
transition: background-color var(--transition-fast);
}
.hamburger::before,
.hamburger::after {
content: '';
position: absolute;
width: 24px;
height: 2px;
background-color: var(--color-gray-900);
transition: transform var(--transition-fast);
}
.hamburger::before {
top: -8px;
}
.hamburger::after {
top: 8px;
}
.nav-toggle[aria-expanded="true"] .hamburger {
background-color: transparent;
}
.nav-toggle[aria-expanded="true"] .hamburger::before {
transform: rotate(45deg);
top: 0;
}
.nav-toggle[aria-expanded="true"] .hamburger::after {
transform: rotate(-45deg);
top: 0;
}
.nav-menu {
display: flex;
list-style: none;
gap: var(--spacing-lg);
}
.nav-link {
text-decoration: none;
color: var(--color-gray-700);
font-weight: 500;
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius-md);
transition: all var(--transition-fast);
}
.nav-link:hover {
color: var(--color-primary);
background-color: var(--color-gray-50);
}
/* Секция Hero */
.hero {
background: linear-gradient(135deg, var(--color-gray-50) 0%, var(--color-white) 100%);
padding: var(--spacing-2xl) 0;
text-align: center;
}
.hero-title {
font-size: var(--font-size-4xl);
font-weight: 700;
color: var(--color-gray-900);
margin-bottom: var(--spacing-md);
line-height: 1.2;
}
.hero-subtitle {
font-size: var(--font-size-xl);
color: var(--color-secondary);
margin-bottom: var(--spacing-xl);
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.hero-actions {
display: flex;
gap: var(--spacing-md);
justify-content: center;
margin-bottom: var(--spacing-2xl);
}
/* Кнопки */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: var(--spacing-md) var(--spacing-lg);
font-size: var(--font-size-base);
font-weight: 600;
text-decoration: none;
border: none;
border-radius: var(--radius-md);
cursor: pointer;
transition: all var(--transition-fast);
min-width: 120px;
}
.btn-primary {
background-color: var(--color-primary);
color: var(--color-white);
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
.btn-secondary {
background-color: var(--color-gray-100);
color: var(--color-gray-900);
}
.btn-secondary:hover {
background-color: var(--color-gray-200);
transform: translateY(-2px);
}
/* Демо-секция */
.demo-section {
margin-top: var(--spacing-2xl);
}
.demo-container {
background-color: var(--color-white);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
box-shadow: var(--shadow-md);
max-width: 500px;
margin: 0 auto;
}
#demo-canvas {
border: 2px solid var(--color-gray-200);
border-radius: var(--radius-md);
width: 100%;
height: auto;
display: block;
margin-bottom: var(--spacing-md);
}
.demo-controls {
display: flex;
gap: var(--spacing-sm);
flex-wrap: wrap;
align-items: center;
}
.demo-btn {
padding: var(--spacing-sm) var(--spacing-md);
background-color: var(--color-gray-100);
border: none;
border-radius: var(--radius-sm);
cursor: pointer;
font-size: var(--font-size-sm);
transition: all var(--transition-fast);
}
.demo-btn:hover {
background-color: var(--color-gray-200);
}
#color-picker {
width: 50px;
height: 36px;
border: none;
border-radius: var(--radius-sm);
cursor: pointer;
}
/* Секция возможностей */
.features {
padding: var(--spacing-2xl) 0;
background-color: var(--color-gray-50);
}
.section-title {
font-size: var(--font-size-3xl);
font-weight: 700;
text-align: center;
margin-bottom: var(--spacing-2xl);
color: var(--color-gray-900);
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--spacing-xl);
}
.feature-card {
background-color: var(--color-white);
padding: var(--spacing-xl);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
text-align: center;
transition: transform var(--transition-normal), box-shadow var(--transition-normal);
}
.feature-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-xl);
}
.feature-icon {
display: flex;
justify-content: center;
margin-bottom: var(--spacing-lg);
color: var(--color-primary);
}
.feature-title {
font-size: var(--font-size-xl);
font-weight: 600;
margin-bottom: var(--spacing-md);
color: var(--color-gray-900);
}
.feature-description {
color: var(--color-secondary);
line-height: 1.6;
}
/* Форма обратной связи */
.contact {
padding: var(--spacing-2xl) 0;
}
.contact-form {
max-width: 600px;
margin: 0 auto;
}
.form-group {
margin-bottom: var(--spacing-lg);
}
.form-label {
display: block;
font-weight: 600;
margin-bottom: var(--spacing-sm);
color: var(--color-gray-900);
}
.form-input,
.form-textarea {
width: 100%;
padding: var(--spacing-md);
border: 2px solid var(--color-gray-200);
border-radius: var(--radius-md);
font-size: var(--font-size-base);
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.form-input:focus,
.form-textarea:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgb(59 130 246 / 0.1);
}
.form-input:invalid,
.form-textarea:invalid {
border-color: var(--color-error);
}
.form-error {
display: none;
color: var(--color-error);
font-size: var(--font-size-sm);
margin-top: var(--spacing-xs);
}
.form-input:invalid ~ .form-error {
display: block;
}
.form-actions {
display: flex;
gap: var(--spacing-md);
justify-content: flex-end;
}
/* Подвал */
.footer {
background-color: var(--color-gray-900);
color: var(--color-gray-100);
padding: var(--spacing-xl) 0;
text-align: center;
}
.footer-links {
margin-top: var(--spacing-md);
display: flex;
gap: var(--spacing-lg);
justify-content: center;
}
.footer-links a {
color: var(--color-gray-400);
text-decoration: none;
transition: color var(--transition-fast);
}
.footer-links a:hover {
color: var(--color-white);
}
/* Responsive Design */
/* Подход Mobile First */
/* Малые планшеты и большие телефоны */
@media (min-width: 640px) {
.container {
padding: 0 var(--spacing-lg);
}
.hero-title {
font-size: var(--font-size-5xl);
}
.features-grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* Планшеты */
@media (min-width: 768px) {
.nav-toggle {
display: none;
}
.nav-menu {
display: flex;
}
.hero-actions {
flex-direction: row;
}
.demo-controls {
justify-content: center;
}
}
/* Десктоп */
@media (min-width: 1024px) {
.hero {
padding: var(--spacing-3xl) 0;
}
.features-grid {
grid-template-columns: repeat(3, 1fr);
}
.form-actions {
justify-content: flex-start;
}
}
/* Широкий десктоп */
@media (min-width: 1280px) {
.container {
padding: 0 var(--spacing-xl);
}
.hero-title {
font-size: var(--font-size-6xl);
}
}
/* Поддержка тёмного режима */
@media (prefers-color-scheme: dark) {
:root {
--color-white: #0f172a;
--color-gray-50: #1e293b;
--color-gray-100: #334155;
--color-gray-900: #f8fafc;
--color-gray-700: #cbd5e1;
--color-gray-200: #475569;
}
.header {
background-color: var(--color-gray-50);
}
.hero {
background: linear-gradient(135deg, var(--color-gray-50) 0%, var(--color-white) 100%);
}
.features {
background-color: var(--color-white);
}
.btn-secondary {
background-color: var(--color-gray-200);
color: var(--color-gray-900);
}
.btn-secondary:hover {
background-color: var(--color-gray-100);
}
}
/* Стили для печати */
@media print {
.nav-toggle,
.hero-actions,
.demo-section,
.contact-form {
display: none;
}
.hero {
padding: var(--spacing-lg) 0;
}
body {
font-size: 12pt;
line-height: 1.4;
}
h1, h2, h3 {
page-break-after: avoid;
}
.feature-card {
break-inside: avoid;
}
}
/* Анимации */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fadeIn 0.6s ease-out;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
.pulse {
animation: pulse 2s infinite;
}
/* Стили фокуса для доступности */
.btn:focus,
.nav-link:focus,
.form-input:focus,
.form-textarea:focus {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
/* Режим высокой контрастности */
@media (prefers-contrast: high) {
:root {
--color-primary: #0000ff;
--color-secondary: #000000;
--color-gray-900: #000000;
--color-gray-100: #ffffff;
}
.btn {
border: 2px solid currentColor;
}
.form-input,
.form-textarea {
border-width: 3px;
}
}
/* Сокращённые анимации */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
3. JavaScript ES6+ с манипуляцией DOM
// Современный JavaScript с возможностями ES6+
// Выбор элементов DOM
const elements = {
// Навигация
navToggle: document.querySelector('.nav-toggle'),
navMenu: document.querySelector('#nav-menu'),
navLinks: document.querySelectorAll('.nav-link'),
// Hero секция
heroTitle: document.querySelector('.hero-title'),
heroActions: document.querySelector('.hero-actions'),
// Демо
canvas: document.querySelector('#demo-canvas'),
demoButtons: document.querySelectorAll('.demo-btn'),
colorPicker: document.querySelector('#color-picker'),
// Форма
contactForm: document.querySelector('.contact-form'),
formInputs: document.querySelectorAll('.form-input'),
// Функции
featureCards: document.querySelectorAll('.feature-card')
};
// State Management
const state = {
isNavOpen: false,
currentColor: '#3b82f6',
isDrawing: false,
lastX: 0,
lastY: 0
};
// Утилиты
const utils = {
// Debounce для производительности
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
// Throttle для событий
throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
},
// Появление элемента с анимацией
animateIn(element, animation = 'fade-in') {
element.style.opacity = '0';
element.classList.add(animation);
// Force reflow
element.offsetHeight;
element.style.opacity = '1';
setTimeout(() => {
element.classList.remove(animation);
element.style.opacity = '';
}, 600);
},
// Плавная прокрутка
smoothScroll(target) {
const element = document.querySelector(target);
if (element) {
element.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
},
// Локальное хранилище
saveToLocalStorage(key, data) {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch (error) {
console.warn('LocalStorage недоступен:', error);
}
},
getFromLocalStorage(key) {
try {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
} catch (error) {
console.warn('Ошибка чтения LocalStorage:', error);
return null;
}
}
};
// Навигация
class Navigation {
constructor() {
this.init();
}
init() {
// Переключение мобильной навигации
if (elements.navToggle) {
elements.navToggle.addEventListener('click', this.toggleNav.bind(this));
}
// Ссылки навигации
elements.navLinks.forEach(link => {
link.addEventListener('click', this.handleNavClick.bind(this));
});
// Закрытие по Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && state.isNavOpen) {
this.closeNav();
}
});
// Закрытие при клике вне меню
document.addEventListener('click', (e) => {
if (state.isNavOpen && !elements.navMenu.contains(e.target) && !elements.navToggle.contains(e.target)) {
this.closeNav();
}
});
}
toggleNav() {
state.isNavOpen = !state.isNavOpen;
this.updateNavUI();
}
openNav() {
state.isNavOpen = true;
this.updateNavUI();
}
closeNav() {
state.isNavOpen = false;
this.updateNavUI();
}
updateNavUI() {
elements.navToggle.setAttribute('aria-expanded', state.isNavOpen);
elements.navMenu.classList.toggle('nav-open', state.isNavOpen);
// Блокировка прокрутки body
document.body.style.overflow = state.isNavOpen ? 'hidden' : '';
}
handleNavClick(e) {
e.preventDefault();
const href = e.target.getAttribute('href');
if (href && href.startsWith('#')) {
utils.smoothScroll(href);
this.closeNav();
}
}
}
// Canvas демо
class CanvasDemo {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.init();
}
init() {
this.setupCanvas();
this.bindEvents();
this.drawInitialContent();
}
setupCanvas() {
// Поддержка High DPI
const dpr = window.devicePixelRatio || 1;
const rect = this.canvas.getBoundingClientRect();
this.canvas.width = rect.width * dpr;
this.canvas.height = rect.height * dpr;
this.ctx.scale(dpr, dpr);
this.canvas.style.width = rect.width + 'px';
this.canvas.style.height = rect.height + 'px';
}
bindEvents() {
// События мыши
this.canvas.addEventListener('mousedown', this.startDrawing.bind(this));
this.canvas.addEventListener('mousemove', this.draw.bind(this));
this.canvas.addEventListener('mouseup', this.stopDrawing.bind(this));
this.canvas.addEventListener('mouseout', this.stopDrawing.bind(this));
// События касания
this.canvas.addEventListener('touchstart', this.handleTouch.bind(this));
this.canvas.addEventListener('touchmove', this.handleTouch.bind(this));
this.canvas.addEventListener('touchend', this.stopDrawing.bind(this));
// Кнопки демо
elements.demoButtons.forEach(btn => {
btn.addEventListener('click', this.handleDemoAction.bind(this));
});
// Выбор цвета
elements.colorPicker.addEventListener('change', (e) => {
state.currentColor = e.target.value;
});
// Изменение размера окна
window.addEventListener('resize', utils.debounce(() => {
this.setupCanvas();
this.drawInitialContent();
}, 250));
}
startDrawing(e) {
state.isDrawing = true;
const rect = this.canvas.getBoundingClientRect();
state.lastX = e.clientX - rect.left;
state.lastY = e.clientY - rect.top;
}
draw(e) {
if (!state.isDrawing) return;
const rect = this.canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
this.ctx.beginPath();
this.ctx.moveTo(state.lastX, state.lastY);
this.ctx.lineTo(x, y);
this.ctx.strokeStyle = state.currentColor;
this.ctx.lineWidth = 3;
this.ctx.lineCap = 'round';
this.ctx.stroke();
state.lastX = x;
state.lastY = y;
}
stopDrawing() {
state.isDrawing = false;
}
handleTouch(e) {
e.preventDefault();
const touch = e.touches[0];
const mouseEvent = new MouseEvent(e.type === 'touchstart' ? 'mousedown' :
e.type === 'touchmove' ? 'mousemove' : 'mouseup', {
clientX: touch.clientX,
clientY: touch.clientY
});
this.canvas.dispatchEvent(mouseEvent);
}
handleDemoAction(e) {
const action = e.target.dataset.action;
switch (action) {
case 'clear':
this.clearCanvas();
break;
case 'animate':
this.animateShapes();
break;
}
}
clearCanvas() {
const rect = this.canvas.getBoundingClientRect();
this.ctx.clearRect(0, 0, rect.width, rect.height);
this.drawInitialContent();
}
drawInitialContent() {
const rect = this.canvas.getBoundingClientRect();
const centerX = rect.width / 2;
const centerY = rect.height / 2;
// Приветственный текст
this.ctx.font = '20px Inter';
this.ctx.fillStyle = state.currentColor;
this.ctx.textAlign = 'center';
this.ctx.fillText('Рисуйте здесь!', centerX, centerY);
}
animateShapes() {
const rect = this.canvas.getBoundingClientRect();
let x = 0;
let y = rect.height / 2;
let dx = 2;
let dy = 1;
let hue = 0;
const animate = () => {
// Стирание следов
this.ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
this.ctx.fillRect(0, 0, rect.width, rect.height);
// Рисование круга
this.ctx.beginPath();
this.ctx.arc(x, y, 20, 0, Math.PI * 2);
this.ctx.fillStyle = `hsl(${hue}, 70%, 50%)`;
this.ctx.fill();
// Обновление позиции
x += dx;
y += dy;
hue += 2;
// Отскок от стен
if (x > rect.width - 20 || x < 20) dx = -dx;
if (y > rect.height - 20 || y < 20) dy = -dy;
// Продолжение анимации
if (hue < 360) {
requestAnimationFrame(animate);
}
};
animate();
}
}
// Валидация форм
class FormValidator {
constructor(form) {
this.form = form;
this.init();
}
init() {
this.form.addEventListener('submit', this.handleSubmit.bind(this));
// Проверка в реальном времени
elements.formInputs.forEach(input => {
input.addEventListener('blur', () => this.validateField(input));
input.addEventListener('input', () => this.clearError(input));
});
}
handleSubmit(e) {
e.preventDefault();
if (this.validateForm()) {
this.submitForm();
} else {
this.showFirstError();
}
}
validateForm() {
let isValid = true;
elements.formInputs.forEach(input => {
if (!this.validateField(input)) {
isValid = false;
}
});
return isValid;
}
validateField(field) {
const value = field.value.trim();
const type = field.type;
const isRequired = field.hasAttribute('required');
let isValid = true;
// Проверка обязательного поля
if (isRequired && !value) {
this.showError(field, 'Это поле обязательно');
isValid = false;
}
// Проверка email
if (type === 'email' && value) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(value)) {
this.showError(field, 'Введите корректный адрес электронной почты');
isValid = false;
}
}
// Проверка имени
if (field.id === 'name' && value) {
if (value.length < 2) {
this.showError(field, 'Имя должно быть не менее 2 символов');
isValid = false;
}
}
if (isValid) {
this.clearError(field);
}
return isValid;
}
showError(field, message) {
field.classList.add('error');
const errorElement = document.getElementById(`${field.id}-error`);
if (errorElement) {
errorElement.textContent = message;
errorElement.style.display = 'block';
}
}
clearError(field) {
field.classList.remove('error');
const errorElement = document.getElementById(`${field.id}-error`);
if (errorElement) {
errorElement.style.display = 'none';
}
}
showFirstError() {
const firstError = this.form.querySelector('.form-input.error');
if (firstError) {
firstError.focus();
firstError.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
submitForm() {
const formData = new FormData(this.form);
const data = Object.fromEntries(formData);
// Имитация API запроса
this.showLoading();
setTimeout(() => {
this.showSuccess();
this.form.reset();
}, 1500);
}
showLoading() {
const submitBtn = this.form.querySelector('button[type="submit"]');
submitBtn.disabled = true;
submitBtn.textContent = 'Отправляется...';
}
showSuccess() {
const submitBtn = this.form.querySelector('button[type="submit"]');
submitBtn.disabled = false;
submitBtn.textContent = 'Отправлено!';
submitBtn.classList.add('success');
setTimeout(() => {
submitBtn.textContent = 'Отправить';
submitBtn.classList.remove('success');
}, 3000);
// Показать сообщение об успехе
this.showMessage('Сообщение успешно отправлено!', 'success');
}
showMessage(text, type = 'info') {
const message = document.createElement('div');
message.className = `message message-${type}`;
message.textContent = text;
this.form.appendChild(message);
utils.animateIn(message);
setTimeout(() => {
message.remove();
}, 5000);
}
}
// Intersection Observer для анимаций при прокрутке
class ScrollAnimations {
constructor() {
this.init();
}
init() {
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.animateElement(entry.target);
observer.unobserve(entry.target);
}
});
}, observerOptions);
// Наблюдение за элементами
elements.featureCards.forEach(card => {
observer.observe(card);
});
// Hero анимация
if (elements.heroTitle) {
utils.animateIn(elements.heroTitle);
}
if (elements.heroActions) {
setTimeout(() => {
utils.animateIn(elements.heroActions);
}, 300);
}
}
animateElement(element) {
utils.animateIn(element);
// Pulse анимация для карточек функций
if (element.classList.contains('feature-card')) {
setTimeout(() => {
element.classList.add('pulse');
setTimeout(() => {
element.classList.remove('pulse');
}, 2000);
}, 1000);
}
}
}
// Инициализация приложения
class App {
constructor() {
this.modules = {};
this.init();
}
init() {
// Проверка готовности DOM
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.start());
} else {
this.start();
}
}
start() {
console.log('🚀 Демо веб-разработки запущено');
// Инициализация модулей
this.modules.navigation = new Navigation();
if (elements.canvas) {
this.modules.canvas = new CanvasDemo(elements.canvas);
}
if (elements.contactForm) {
this.modules.form = new FormValidator(elements.contactForm);
}
this.modules.scrollAnimations = new ScrollAnimations();
// Мониторинг производительности
this.initPerformanceMonitoring();
// Регистрация Service Worker
this.registerServiceWorker();
}
initPerformanceMonitoring() {
// Performance страницы при загрузке
window.addEventListener('load', () => {
const perfData = performance.getEntriesByType('navigation')[0];
const loadTime = perfData.loadEventEnd - perfData.loadEventStart;
console.log(`⚡ Страница загружена за ${loadTime}ms`);
// Предупреждение о медленной загрузке
if (loadTime > 3000) {
console.warn('⚠️ Обнаружена медленная загрузка');
}
});
// Largest Contentful Paint
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log(`🎨 Largest Contentful Paint: ${lastEntry.startTime}ms`);
}).observe({ entryTypes: ['largest-contentful-paint'] });
}
async registerServiceWorker() {
if ('serviceWorker' in navigator) {
try {
const registration = await navigator.serviceWorker.register('/sw.js');
console.log('✅ Service Worker зарегистрирован:', registration.scope);
} catch (error) {
console.log('❌ Ошибка регистрации Service Worker:', error);
}
}
}
}
// Запуск приложения
const app = new App();
// Экспорт для модульной системы
if (typeof module !== 'undefined' && module.exports) {
module.exports = { App, Navigation, CanvasDemo, FormValidator, ScrollAnimations, utils };
}
4. Service Worker для офлайн-функциональности
// sw.js - Service Worker для кеширования и офлайн-функциональности
const CACHE_NAME = 'webdev-demo-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles.css',
'/script.js',
'/logo.svg',
'/favicon.svg'
];
// Установка Service Worker
self.addEventListener('install', (event) => {
console.log('🔧 Service Worker installing...');
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => {
console.log('📦 Caching app shell');
return cache.addAll(urlsToCache);
})
.then(() => {
console.log('✅ App shell cached successfully');
return self.skipWaiting();
})
);
});
// Активация Service Worker
self.addEventListener('activate', (event) => {
console.log('🔄 Service Worker activating...');
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
console.log('🗑️ Deleting old cache:', cacheName);
return caches.delete(cacheName);
}
})
);
}).then(() => {
console.log('✅ Service Worker activated');
return self.clients.claim();
})
);
});
// Обработка запросов - сначала из сети, затем кеш
self.addEventListener('fetch', (event) => {
const { request } = event;
const url = new URL(request.url);
// Только для HTTP/HTTPS-запросов
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
return;
}
event.respondWith(
caches.match(request)
.then((response) => {
// Cache Hit - вернуть закешированный ответ
if (response) {
console.log('📋 Serving from cache:', request.url);
return response;
}
// Запрос из сети
console.log('🌐 Fetching from network:', request.url);
return fetch(request)
.then((response) => {
// Проверка валидности ответа
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// Клонирование ответа для кеширования
const responseToCache = response.clone();
// Кеширование успешных ответов
if (shouldCache(request)) {
caches.open(CACHE_NAME)
.then((cache) => {
console.log('💾 Caching new resource:', request.url);
cache.put(request, responseToCache);
});
}
return response;
})
.catch(() => {
// Сеть недоступна - попытаемся получить из кеша
console.log('❌ Network failed, trying cache for:', request.url);
return caches.match(request);
});
})
);
});
// Вспомогательная функция для определения, нужно ли кешировать запрос
function shouldCache(request) {
const url = new URL(request.url);
// Не кешируем API-запросы и внешние ресурсы
if (url.pathname.startsWith('/api/') || url.origin !== self.location.origin) {
return false;
}
// Кешируем статические файлы
const staticExtensions = ['.css', '.js', '.svg', '.png', '.jpg', '.jpeg', '.webp'];
const hasStaticExtension = staticExtensions.some(ext => url.pathname.endsWith(ext));
return hasStaticExtension || url.pathname === '/';
}
// Фоновая синхронизация для офлайн-операций
self.addEventListener('sync', (event) => {
if (event.tag === 'background-sync') {
console.log('🔄 Background sync triggered');
event.waitUntil(
// Здесь могут синхронизироваться офлайн-операции
new Promise((resolve) => {
setTimeout(() => {
console.log('✅ Background sync completed');
resolve();
}, 1000);
})
);
}
});
// Push-уведомления
self.addEventListener('push', (event) => {
console.log('📨 Push message received');
const options = {
body: event.data.text(),
icon: '/logo.svg',
badge: '/favicon.svg',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 1
},
actions: [
{
action: 'explore',
title: 'Explore',
icon: '/images/checkmark.png'
},
{
action: 'close',
title: 'Close',
icon: '/images/xmark.png'
}
]
};
event.waitUntil(
self.registration.showNotification('WebDev Demo', options)
);
});
// Обработка клика по уведомлению
self.addEventListener('notificationclick', (event) => {
console.log('🔔 Notification clicked');
event.notification.close();
if (event.action === 'explore') {
event.waitUntil(
clients.openWindow('/')
);
}
});
Обзор HTML5 семантических элементов
| Элемент | Описание | Использование |
|---|---|---|
| header | Шапка страницы | Логотип, навигация |
| nav | Навигация | Меню, ссылки |
| main | Основное содержимое | Первичный контент |
| section | Раздел | Тематические блоки |
| article | Статья | Самостоятельные материалы |
| aside | Боковая панель | Вспомогательная информация |
| footer | Подвал страницы | Копирайт, ссылки |
Техники CSS3 макетирования
Flexbox
.container {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
}
.item {
flex: 1 1 300px;
margin: 1rem;
}
Grid
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
Container Queries
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
Возможности JavaScript ES6+
Arrow Functions
const add = (a, b) => a + b;
const users = data.map(item => item.name);
Template Literals
const message = `Hallo ${name}, du hast ${count} Nachrichten`;
Destructuring
const {name, email} = user;
const [first, second] = array;
Spread/Rest
const newArray = [...oldArray, newItem];
const sum = (...numbers) => numbers.reduce((a, b) => a + b);
Async/Await
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Error:', error);
}
}
Адаптивный дизайн. Точки перелома
/* Мобильный подход в первую очередь */
/* Небольшие телефоны */
@media (min-width: 320px) { }
/* Большие телефоны */
@media (min-width: 480px) { }
/* Планшеты */
@media (min-width: 768px) { }
/* Десктоп */
@media (min-width: 1024px) { }
/* Большой десктоп */
@media (min-width: 1200px) { }
Методы манипуляции DOM
| Метод | Описание | Пример |
|---|---|---|
| querySelector | Выбрать элемент | document.querySelector('.class') |
| createElement | Создать элемент | document.createElement('div') |
| appendChild | Добавить элемент | parent.appendChild(child) |
| classList | Управлять классами | element.classList.add('active') |
| addEventListener | Привязать событие | element.addEventListener('click', handler) |
| setAttribute | Установить атрибут | element.setAttribute('data-id', '123') |
CSS3 анимации
Transitions
.button {
transition: all 0.3s ease-in-out;
}
.button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
Keyframes
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.element {
animation: fadeIn 0.6s ease-out;
}
Оптимизация производительности веб-приложений
Lazy Loading
// Images
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
Code Splitting
// Dynamic Import
const loadModule = async () => {
const module = await import('./heavy-module.js');
module.doSomething();
};
Лучшие практики доступности
Семантическая разметка
<nav aria-label="Hauptnavigation">
<ul>
<li><a href="#" aria-current="page">Home</a></li>
<li><a href="#">About</a></li>
</ul>
</nav>
Атрибуты ARIA
<button aria-expanded="false" aria-controls="menu">
Menü
</button>
<div id="menu" hidden>
<!-- Menu content -->
</div>
Навигация с клавиатуры
.focusable:focus {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
Преимущества и недостатки
Преимущества современной веб-разработки
- Кроссплатформенность: один код для всех устройств
- Адаптивность: оптимальный вид на любом экране
- Интерактивность: богатый пользовательский опыт
- SEO-оптимизация: хорошие позиции в поисковых системах
- Доступность: поддержка для пользователей с ограничениями
Недостатки
- Сложность: много технологий к изучению
- Совместимость браузеров: разная поддержка возможностей
- Производительность: требуется постоянная оптимизация
- Безопасность: необходимы защитные меры
Типичные вопросы на экзамене
-
В чём различие между HTML, CSS и JavaScript? HTML структурирует содержимое, CSS определяет внешний вид, JavaScript добавляет интерактивность.
-
Объясните адаптивный дизайн! Это подстройка интерфейса под разные размеры экранов с помощью Media Queries и гибких макетов.
-
Что такое DOM и как его изменять? DOM это программируемое представление HTML-документа. Изменение происходит через JavaScript методы типа querySelector, createElement, appendChild.
-
Когда применять Flexbox, а когда Grid? Flexbox используется для одномерных макетов (строки или колонки), Grid для двумерных макетов.
Основные источники информации
- https://developer.mozilla.org/de/docs/Web
- https://www.w3.org/TR/html5/
- https://www.w3.org/Style/CSS/
Рекомендуемая литература: Веб-разработка
Keine Bücher für Kategorie "web-development" gefunden.



