← Назад к вопросам
Как определить какие теги можно вкладывать?
2.2 Middle🔥 181 комментариев
#Soft Skills и рабочие процессы
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Вложение HTML-тегов: правила и проверка
В HTML существуют строгие правила о том, какие теги можно вкладывать внутрь других. Это называется "content model" каждого элемента. Рассмотрим способы проверки допустимости вложений.
1. W3C Спецификация — источник истины
Каждый HTML-тег имеет определённый "content model":
// Примеры правил:
// <p> может содержать только inline элементы, НЕ может содержать <div>, <p>
// <div> может содержать block и inline элементы
// <ul> может содержать только <li> (или <script>, <template>)
// <button> может содержать только phrasing content, НЕ может содержать <div>
// Базовая типизация контента
const contentModels = {
"p": "phrasing", // только inline
"div": "flow", // block и inline
"ul": "listItem", // только <li>
"button": "phrasing", // только inline
"form": "flow", // block и inline
"table": "tableContent", // только <tr>/<caption>/<colgroup>
"thead": "tableSection", // только <tr>
"tr": "tableCell", // только <td>/<th>
"select": "option", // только <option>/<optgroup>
"datalist": "option" // только <option>
};
2. Программная проверка в JavaScript
Создай утилиту для валидации вложений:
// Функция проверки допустимости вложения
function isValidChild(parentTag, childTag) {
const rules = {
"p": { forbidden: ["address", "article", "aside", "blockquote", "details", "div", "dl", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "main", "nav", "ol", "pre", "section", "table", "ul"] },
"ul": { allowed: ["li", "script", "template"] },
"ol": { allowed: ["li", "script", "template"] },
"table": { allowed: ["caption", "colgroup", "tbody", "tfoot", "thead"] },
"thead": { allowed: ["tr"] },
"tbody": { allowed: ["tr"] },
"tr": { allowed: ["td", "th"] },
"button": { forbidden: ["a", "button", "form", "input", "select", "textarea"] },
"label": { forbidden: ["label"] }
};
const rule = rules[parentTag];
if (!rule) return true; // Неизвестный тег, разрешаем
if (rule.allowed) {
return rule.allowed.includes(childTag);
}
if (rule.forbidden) {
return !rule.forbidden.includes(childTag);
}
return true;
}
// Использование
console.log(isValidChild("p", "div")); // false - неправильно
console.log(isValidChild("div", "p")); // true - правильно
console.log(isValidChild("ul", "li")); // true - правильно
console.log(isValidChild("ul", "div")); // false - неправильно
console.log(isValidChild("button", "a")); // false - неправильно
3. Валидация DOM при вставке элемента
function validateAndInsertElement(parentElement, childElement) {
const parentTag = parentElement.tagName.toLowerCase();
const childTag = childElement.tagName.toLowerCase();
if (!isValidChild(parentTag, childTag)) {
console.warn(`Warning: <${childTag}> cannot be placed inside <${parentTag}>`);
// Вариант 1: Отказать
throw new Error(`Invalid nesting: <${childTag}> in <${parentTag}>`);
// Вариант 2: Авто-исправить (вставить после родителя)
// parentElement.parentElement.insertBefore(childElement, parentElement.nextSibling);
}
parentElement.appendChild(childElement);
}
// Пример с React
import { useEffect } from "react";
function validateReactChildren(tag, children) {
// Проверка типов для React компонентов
React.Children.forEach(children, child => {
if (!React.isValidElement(child)) return;
const childTag = child.type?.toLowerCase?.();
if (!isValidChild(tag, childTag)) {
console.error(`Invalid children: <${childTag}> inside <${tag}>`);
}
});
}
4. TypeScript типизация допустимых детей
// Строгая типизация в TypeScript
type FlowContent = "p" | "div" | "section" | "article" | "ul" | "ol" | "form";
type PhrasingContent = "span" | "a" | "strong" | "em" | "button" | "input";
type ListItemContent = "li";
interface ContentModel {
p: PhrasingContent[];
div: FlowContent[];
ul: ListItemContent[];
button: PhrasingContent[];
}
// Компонент с типизованными детьми
interface DivProps {
children: React.ReactElement<{ type: FlowContent }>;
}
function StrictDiv({ children }: DivProps) {
// TypeScript проверит типы на компиляции
return <div>{children}</div>;
}
5. Инструменты для проверки
// Браузер автоматически перемещает некорректные элементы
// Пример: если вставить <div> в <p>, браузер автоматически закроет <p>
const p = document.createElement("p");
const div = document.createElement("div");
p.appendChild(div); // Браузер автоматически переместит div после p
console.log(p.innerHTML); // "" - div был удалён!
// Проверить свежесть через DOM API
function checkValidation(element) {
const parent = element.parentElement;
if (!parent) return true;
// После вставки проверить остался ли элемент на месте
const originalParent = element.parentElement;
return originalParent === parent;
}
Рекомендация
Используй комбинацию:
- Изучи W3C спецификацию для основных правил
- Реализуй
isValidChild()функцию в проекте - Используй TypeScript для типизации
- Доверяй браузеру — он сам исправит некорректные вложения
- В React проверяй детей через
React.Children.forEach()