📘 Чому валідація важлива?
✅ SEO — пошукові системи краще індексують валідний код
✅ Доступність — screen readers та assistive technologies потребують семантично правильного HTML
✅ Кросбраузерність — валідний код однаково працює в різних браузерах
✅ Підтримка — чистий код легше читати та модифікувати
✅ Performance — браузери швидше парсять валідний HTML
Частина 1: Ручна Валідація через W3C
W3C Markup Validation Service
1
Онлайн валідація HTML
Перейдіть на https://validator.w3.org/
Оберіть один з методів перевірки:
Validate by URI — введіть URL вашого сайту
Validate by File Upload — завантажте HTML файл
Validate by Direct Input — вставте HTML код
Натисніть Check
Проаналізуйте результати:
Errors — критичні помилки (необхідно виправити)
Warnings — попередження (рекомендовано виправити)
Типові HTML помилки:
❌ Помилка 1: Відсутній DOCTYPE
<!-- НЕПРАВИЛЬНО -->
<html>
<head><title>Page</title></head>
<body>Content</body>
</html>
✅ Правильно:
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<title>Page</title>
</head>
<body>Content</body>
</html>
❌ Помилка 2: Незакритий тег
<div>
<p>Paragraph without closing tag
<p>Another paragraph</p>
</div>
✅ Правильно:
<div>
<p>Paragraph with closing tag</p>
<p>Another paragraph</p>
</div>
❌ Помилка 3: Вкладені посилання
<a href="page1.html">
Link with nested <a href="page2.html">link</a>
</a>
✅ Правильно:
<a href="page1.html">First link</a>
<a href="page2.html">Second link</a>
W3C CSS Validation Service
2
Онлайн валідація CSS
Перейдіть на https://jigsaw.w3.org/css-validator/
Введіть URL або вставте CSS код
Оберіть профіль:
CSS level 3 (рекомендовано)
CSS level 2.1
CSS level 1
Натисніть Check
Типові CSS помилки:
❌ Помилка 1: Невалідні властивості
.box {
colour: red; /* помилка: має бути color */
heigth: 100px; /* помилка: має бути height */
}
❌ Помилка 2: Відсутні одиниці виміру
.box {
width: 100; /* має бути 100px */
margin: 20; /* має бути 20px */
}
❌ Помилка 3: Vendor prefixes без стандартної властивості
.box {
-webkit-transform: rotate(45deg);
/* відсутня стандартна transform властивість */
}
✅ Правильно:
.box {
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg); /* стандартна властивість останньою */
}
Частина 2: Автоматична Валідація з CLI
html-validate (Node.js)
1
Встановлення та налаштування
# Встановлення
npm install --save-dev html-validate
# Запуск валідації
npx html-validate "**/*.html"
# Валідація конкретного файлу
npx html-validate index.html
# З детальним виводом
npx html-validate --formatter stylish "**/*.html"
Створіть .htmlvalidate.json у корені проекту:
{
"extends": ["html-validate:recommended"],
"rules": {
"close-order": "error",
"void-style": ["error", { "style": "selfclose" }],
"no-trailing-whitespace": "error",
"attr-quotes": ["error", { "style": "double" }],
"doctype-style": ["error", { "style": "html5" }],
"element-required-attributes": "error",
"no-deprecated-elements": "error"
},
"elements": [
"html5"
]
}
Додайте script у package.json:
{
"scripts": {
"validate:html": "html-validate \"**/*.html\"",
"validate:html:fix": "html-validate --formatter stylish \"**/*.html\""
}
}
stylelint (CSS Linter)
2
Налаштування stylelint
# Встановлення
npm install --save-dev stylelint stylelint-config-standard
# Запуск
npx stylelint "**/*.css"
# Автоматичне виправлення
npx stylelint "**/*.css" --fix
Створіть .stylelintrc.json:
{
"extends": "stylelint-config-standard",
"rules": {
"indentation": 2,
"string-quotes": "double",
"no-duplicate-selectors": true,
"color-hex-case": "lower",
"color-hex-length": "short",
"color-named": "never",
"selector-combinator-space-after": "always",
"selector-attribute-quotes": "always",
"selector-attribute-operator-space-before": "never",
"selector-attribute-operator-space-after": "never",
"declaration-block-trailing-semicolon": "always",
"declaration-colon-space-before": "never",
"declaration-colon-space-after": "always",
"number-leading-zero": "always",
"function-url-quotes": "always",
"font-family-name-quotes": "always-where-recommended",
"comment-whitespace-inside": "always",
"rule-empty-line-before": [
"always",
{
"except": ["first-nested"],
"ignore": ["after-comment"]
}
],
"selector-pseudo-element-colon-notation": "double",
"selector-pseudo-class-parentheses-space-inside": "never",
"media-feature-range-operator-space-before": "always",
"media-feature-range-operator-space-after": "always",
"media-feature-parentheses-space-inside": "never",
"media-feature-colon-space-before": "never",
"media-feature-colon-space-after": "always"
}
}
Частина 3: Prettier (Code Formatting)
1
Автоматичне форматування коду
# Встановлення
npm install --save-dev prettier
# Форматування всіх HTML/CSS файлів
npx prettier --write "**/*.{html,css,js}"
# Перевірка без змін
npx prettier --check "**/*.{html,css,js}"
Створіть .prettierrc.json:
{
"semi": true,
"trailingComma": "es5",
"singleQuote": false,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf",
"htmlWhitespaceSensitivity": "css",
"proseWrap": "preserve",
"quoteProps": "as-needed"
}
Додайте у package.json:
{
"scripts": {
"format": "prettier --write \"**/*.{html,css,js,json,md}\"",
"format:check": "prettier --check \"**/*.{html,css,js,json,md}\""
}
}
Частина 4: Pre-commit Hooks (Husky + lint-staged)
1
Автоматична валідація перед commit
# Встановлення
npm install --save-dev husky lint-staged
# Ініціалізація husky
npx husky init
# Створення pre-commit hook
echo "npx lint-staged" > .husky/pre-commit
Налаштування package.json:
{
"lint-staged": {
"*.html": [
"html-validate",
"prettier --write"
],
"*.css": [
"stylelint --fix",
"prettier --write"
],
"*.{js,jsx}": [
"eslint --fix",
"prettier --write"
]
}
}
💡 Як це працює:
При кожному git commit автоматично запускається:
HTML валідація (html-validate)
CSS лінтинг (stylelint) з автофіксом
Форматування коду (prettier)
Якщо є помилки — commit блокується ❌
Якщо все ОК — commit виконується ✅
Частина 5: CI/CD Integration
GitHub Actions Workflow
1
Автоматична валідація в CI
Створіть .github/workflows/validate.yml:
name: HTML/CSS Validation
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Validate HTML
run: npm run validate:html
- name: Lint CSS
run: npx stylelint "**/*.css"
- name: Check code formatting
run: npm run format:check
- name: Upload validation results
if: failure()
uses: actions/upload-artifact@v3
with:
name: validation-errors
path: validation-report.txt
Netlify Build Settings
# netlify.toml
[build]
command = "npm run validate:all && npm run build"
publish = "build"
[build.environment]
NODE_VERSION = "20"
[[plugins]]
package = "netlify-plugin-checklinks" # Перевірка broken links
[[plugins]]
package = "@netlify/plugin-lighthouse" # Performance audit
Частина 6: VS Code Extensions
Налаштуй те VS Code (.vscode/settings.json):
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": "explicit"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"css.validate": false,
"stylelint.validate": ["css", "scss", "sass"],
"html.validate.scripts": true,
"html.validate.styles": true
}
Частина 7: Accessibility Validation
axe DevTools (Browser Extension)
Встановіть розширення для браузера:
Chrome: axe DevTools - Web Accessibility Testing
Firefox: axe DevTools
Відкрийте DevTools (F12)
Перейдіть на вкладку axe DevTools
Натисніть Scan ALL of my page
Проаналізуйте:
Critical — критичні проблеми доступності
Serious — серйозні проблеми
Moderate — середні проблеми
Minor — незначні проблеми
pa11y (Command Line Tool)
# Встановлення
npm install --save-dev pa11y
# Запуск
npx pa11y https://example.com
# З детальним звітом
npx pa11y --reporter html --output report.html https://example.com
# CI integration
npx pa11y-ci --sitemap https://example.com/sitemap.xml
Частина 8: Performance Validation
Lighthouse (Chrome DevTools)
Відкрийте DevTools (F12) → вкладка Lighthouse
Оберіть категорії:
✅ Performance
✅ Accessibility
✅ Best Practices
✅ SEO
✅ PWA (опціонально)
Натисніть Analyze page load
Отримайте score (0-100) та рекомендації
PageSpeed Insights API
# Отримання звіту через API
curl "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://example.com&category=PERFORMANCE&category=ACCESSIBILITY&category=SEO&category=BEST_PRACTICES" \
| jq '.lighthouseResult.categories'
Частина 9: Code Quality Tools (ESLint, TypeScript)
ESLint для JavaScript валідації
1
Налаштування ESLint
Встановіть ESLint:
npm install --save-dev eslint
Ініціалізація:
npx eslint --init
# Або швидкий старт з популярними конфігами
npm install --save-dev eslint-config-airbnb-base eslint-plugin-import
Створіть .eslintrc.json:
{
"extends": ["airbnb-base"],
"env": {
"browser": true,
"es2021": true
},
"rules": {
"no-console": "warn",
"no-unused-vars": "error",
"prefer-const": "error",
"quotes": ["error", "single"],
"semi": ["error", "always"]
}
}
Додайте script до package.json:
{
"scripts": {
"lint:js": "eslint src/**/*.js",
"lint:js:fix": "eslint src/**/*.js --fix"
}
}
TypeScript для Type Safety
# Встановлення TypeScript
npm install --save-dev typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitAny": true,
"strictNullChecks": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
// .eslintrc.json для TypeScript
{
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-function-return-type": "warn"
}
}
Частина 10: Advanced stylelint Rules
Custom stylelint конфігурація
// .stylelintrc.json - розширена конфігурація
{
"extends": [
"stylelint-config-standard",
"stylelint-config-rational-order" // Впорядкування CSS властивостей
],
"plugins": [
"stylelint-order",
"stylelint-scss",
"stylelint-high-performance-animation"
],
"rules": {
"color-hex-length": "short",
"color-named": "never",
"font-family-name-quotes": "always-where-recommended",
"font-weight-notation": "numeric",
"max-nesting-depth": 3,
"selector-max-id": 0,
"selector-max-universal": 1,
"selector-class-pattern": "^[a-z][a-z0-9-]*$",
"declaration-no-important": true,
"order/properties-alphabetical-order": null,
"order/order": [
"custom-properties",
"declarations"
],
"plugin/no-low-performance-animation-properties": true
}
}
SCSS/SASS валідація
npm install --save-dev stylelint-config-sass-guidelines
// .stylelintrc.json для SCSS
{
"extends": "stylelint-config-sass-guidelines",
"rules": {
"max-nesting-depth": 3,
"selector-max-compound-selectors": 3,
"selector-no-qualifying-type": [true, {
"ignore": ["attribute", "class"]
}]
}
}
Частина 11: Browser Compatibility Testing
Autoprefixer для CSS
npm install --save-dev postcss autoprefixer
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')({
overrideBrowserslist: [
'> 1%',
'last 2 versions',
'not dead',
'not ie 11'
]
})
]
};
/* Input CSS */
.calculator {
display: flex;
user-select: none;
}
/* Output CSS після autoprefixer */
.calculator {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
Browserslist конфігурація
// package.json
{
"browserslist": [
"defaults",
"not IE 11",
"maintained node versions",
"> 0.2%",
"last 2 versions",
"Firefox ESR",
"not dead"
]
}
# Перевірити які браузери підтримуються
npx browserslist
# Результат:
# and_chr 120
# and_ff 121
# and_qq 14.9
# chrome 120
# chrome 119
# edge 120
# firefox 121
# ...
Can I Use CLI
npm install -g caniuse-cmd
# Перевірити підтримку CSS Grid
caniuse grid
# Перевірити підтримку Flexbox
caniuse flexbox
# Перевірити підтримку CSS Custom Properties
caniuse css-variables
Частина 12: SEO Validation Tools
Meta Tags Validator
// seo-validator.js
const cheerio = require('cheerio');
const fs = require('fs');
function validateSEO(htmlFile) {
const html = fs.readFileSync(htmlFile, 'utf8');
const $ = cheerio.load(html);
const errors = [];
// Перевірка title
const title = $('title').text();
if (!title) errors.push('❌ Missing
');
if (title.length < 30) errors.push('⚠️ Title too short (< 30 chars)');
if (title.length > 60) errors.push('⚠️ Title too long (> 60 chars)');
// Перевірка meta description
const description = $('meta[name="description"]').attr('content');
if (!description) errors.push('❌ Missing meta description');
if (description && description.length < 120) errors.push('⚠️ Description too short');
if (description && description.length > 160) errors.push('⚠️ Description too long');
// Перевірка h1
const h1Count = $('h1').length;
if (h1Count === 0) errors.push('❌ Missing ');
if (h1Count > 1) errors.push('⚠️ Multiple tags');
// Перевірка images alt
const imagesWithoutAlt = $('img:not([alt])').length;
if (imagesWithoutAlt > 0) {
errors.push(`❌ ${imagesWithoutAlt} images without alt attribute`);
}
// Перевірка canonical
const canonical = $('link[rel="canonical"]').attr('href');
if (!canonical) errors.push('⚠️ Missing canonical URL');
// Перевірка Open Graph
const ogTitle = $('meta[property="og:title"]').attr('content');
const ogDescription = $('meta[property="og:description"]').attr('content');
const ogImage = $('meta[property="og:image"]').attr('content');
if (!ogTitle) errors.push('⚠️ Missing og:title');
if (!ogDescription) errors.push('⚠️ Missing og:description');
if (!ogImage) errors.push('⚠️ Missing og:image');
return errors;
}
// Використання
const errors = validateSEO('index.html');
if (errors.length > 0) {
console.log('SEO Validation Errors:');
errors.forEach(err => console.log(err));
process.exit(1);
} else {
console.log('✅ SEO validation passed!');
}
Structured Data Validator
# Google Structured Data Testing Tool (CLI)
npm install -g schema-dts-gen
# Перевірка JSON-LD
npx schema-dts-gen --validate calculator-schema.json
// structured-data-validator.js
const cheerio = require('cheerio');
function validateStructuredData(html) {
const $ = cheerio.load(html);
const scripts = $('script[type="application/ld+json"]');
scripts.each((i, script) => {
try {
const data = JSON.parse($(script).html());
// Перевірка обов'язкових полів
if (!data['@context']) console.error('❌ Missing @context');
if (!data['@type']) console.error('❌ Missing @type');
console.log(`✅ Valid JSON-LD: ${data['@type']}`);
} catch (e) {
console.error('❌ Invalid JSON-LD:', e.message);
}
});
}
Частина 13: Security Validation
Content Security Policy (CSP) Validator
// csp-validator.js
const cheerio = require('cheerio');
function validateCSP(html) {
const $ = cheerio.load(html);
const csp = $('meta[http-equiv="Content-Security-Policy"]').attr('content');
if (!csp) {
console.warn('⚠️ Missing Content-Security-Policy');
return;
}
const directives = csp.split(';').map(d => d.trim());
const policies = {};
directives.forEach(directive => {
const [key, ...values] = directive.split(/\s+/);
policies[key] = values;
});
// Перевірки
if (!policies['default-src']) {
console.error('❌ Missing default-src directive');
}
if (policies['script-src']?.includes("'unsafe-eval'")) {
console.warn("⚠️ unsafe-eval in script-src (security risk)");
}
if (!policies['upgrade-insecure-requests']) {
console.warn('⚠️ Consider adding upgrade-insecure-requests');
}
console.log('✅ CSP configured');
}
Subresource Integrity (SRI) Validator
# Генерація SRI hash
curl https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css | \
openssl dgst -sha384 -binary | \
openssl base64 -A
# Результат: sha384-9ndCyUa...
Частина 14: Automated Testing в CI/CD
Комплексний GitHub Actions Workflow
# .github/workflows/validation.yml
name: Validation Pipeline
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Validate HTML
run: npm run validate:html
- name: Lint CSS
run: npm run lint:css
- name: Lint JavaScript
run: npm run lint:js
- name: Check Prettier
run: npm run format:check
- name: Accessibility Audit
run: |
npm run build
npm run start &
sleep 5
npx pa11y-ci --sitemap http://localhost:3000/sitemap.xml
- name: Lighthouse CI
uses: treosh/lighthouse-ci-action@v10
with:
urls: |
http://localhost:3000
http://localhost:3000/calculator
uploadArtifacts: true
temporaryPublicStorage: true
- name: SEO Validation
run: node scripts/seo-validator.js
- name: Check Broken Links
uses: lycheeverse/lychee-action@v1
with:
args: --verbose --no-progress './**/*.html' './**/*.md' --exclude-path '.git'
- name: Upload Reports
if: failure()
uses: actions/upload-artifact@v3
with:
name: validation-reports
path: reports/
Pre-deployment Checklist Script
// scripts/pre-deploy-check.js
const { execSync } = require('child_process');
function runCheck(name, command) {
console.log(`\n🔍 Running: ${name}...`);
try {
execSync(command, { stdio: 'inherit' });
console.log(`✅ ${name} passed`);
return true;
} catch (error) {
console.error(`❌ ${name} failed`);
return false;
}
}
const checks = [
['HTML Validation', 'npm run validate:html'],
['CSS Linting', 'npm run lint:css'],
['JavaScript Linting', 'npm run lint:js'],
['Prettier Check', 'npm run format:check'],
['TypeScript Check', 'npx tsc --noEmit'],
['Unit Tests', 'npm test'],
['Build', 'npm run build']
];
console.log('🚀 Pre-deployment validation started\n');
const results = checks.map(([name, cmd]) => runCheck(name, cmd));
console.log('\n📊 Summary:');
console.log(`✅ Passed: ${results.filter(Boolean).length}`);
console.log(`❌ Failed: ${results.filter(r => !r).length}`);
if (results.every(Boolean)) {
console.log('\n🎉 All checks passed! Ready to deploy.');
process.exit(0);
} else {
console.log('\n⛔ Some checks failed. Fix them before deploying.');
process.exit(1);
}
// package.json
{
"scripts": {
"pre-deploy": "node scripts/pre-deploy-check.js",
"deploy": "npm run pre-deploy && npm run deploy:prod"
}
}
Висновок
Автоматизація валідації HTML/CSS — це інвестиція у якість, яка окупається:
✅ Автоматичний контроль якості перед кожним commit
✅ Раннє виявлення помилок до потрапляння в production
✅ Єдиний стандарт коду в команді
✅ Покращення SEO та доступності
🚀 Рекомендований workflow:
Встановіть html-validate + stylelint + prettier
Налаштуйте pre-commit hooks з husky та lint-staged
Інтегруйте у CI/CD pipeline (GitHub Actions/GitLab CI)
Використовуйте VS Code extensions для real-time фідбеку
Періодично запускайте accessibility audit (axe/pa11y)
Моніторьте performance через Lighthouse