Как поддерживать языки с направлением текста справа налево (RTL) в Next.js (Pages Router) v16
Зеркальное отображение макетов для арабского и иврита
Проблема
Большинство веб-макетов предполагают текстовый поток слева направо. Навигационные меню закреплены слева, контент читается слева направо, а отступы задаются с помощью таких свойств, как margin-left или padding-right. Когда приложение переводится на арабский или иврит, эти языки читаются справа налево, и весь визуальный макет должен быть зеркально отражен, чтобы соответствовать. Без зеркального отображения пользователи сталкиваются с дезориентирующим интерфейсом, где визуальная иерархия противоречит их естественному направлению чтения, что делает навигацию запутанной, а приложение кажется недоработанным.
Проблема выходит за рамки выравнивания текста. Физические CSS-свойства, такие как left, right, margin-left и padding-right, привязаны к фиксированным позициям на экране, а не к потоку контента. Когда направление текста меняется, эти свойства остаются привязанными к тем же физическим краям, что мешает макету адаптироваться естественным образом.
Решение
Установите атрибут направления текста документа в соответствии с текущей локалью, чтобы браузеры автоматически изменяли поток макета для языков с направлением справа налево. Замените физические CSS-свойства на логические свойства, которые ссылаются на поток контента, а не на позиции на экране. Логические свойства, такие как margin-inline-start и padding-inline-end, автоматически сопоставляются с правильным физическим краем в зависимости от направления текста, позволяя макетам зеркально отображаться без дополнительного кода или условного стиля.
Этот подход создает независимые от направления макеты, которые корректно работают как для языков с направлением слева направо, так и для языков с направлением справа налево, без дублирования стилей или добавления сложной логики.
Шаги
1. Создайте помощник для определения направления текста по локали
Логические свойства адаптируются в зависимости от направления текста: margin-inline-start эквивалентен margin-left в контексте слева направо и margin-right в контексте справа налево. Создайте утилитную функцию, которая сопоставляет локали с их направлением текста.
export function getDirection(locale: string): "ltr" | "rtl" {
const rtlLocales = ["ar", "he", "fa", "ur"];
return rtlLocales.includes(locale) ? "rtl" : "ltr";
}
Эта функция определяет языки с направлением справа налево и возвращает соответствующее значение направления для использования в HTML и CSS.
2. Установите атрибут направления документа
Классы пользовательских документов могут переопределять метод render, чтобы настроить HTML-элемент с такими атрибутами, как lang и dir. Создайте пользовательский документ, чтобы установить атрибут dir для корневого HTML-элемента на основе текущей локали.
import Document, {
Html,
Head,
Main,
NextScript,
DocumentContext,
} from "next/document";
import { getDirection } from "../utils/direction";
class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const initialProps = await Document.getInitialProps(ctx);
return initialProps;
}
render() {
const locale = this.props.__NEXT_DATA__.locale || "en";
const dir = getDirection(locale);
return (
<Html lang={locale} dir={dir}>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
Маршрутизатор Next.js предоставляет текущую активную локаль через свойство locale. Документ считывает локаль из данных маршрутизации Next.js и применяет соответствующее направление к HTML-элементу, обеспечивая поддержку RTL на уровне браузера.
3. Замените физические CSS-свойства на их логические эквиваленты
Логические свойства, такие как margin-inline-start, padding-inline-start и их сокращенные формы margin-inline и padding-inline, автоматически сопоставляются с физическими свойствами в зависимости от режима письма и направления. Обновите стили ваших компонентов, чтобы использовать свойства, зависящие от потока.
export default function Navigation() {
return (
<nav className="nav">
<ul className="nav-list">
<li className="nav-item">Home</li>
<li className="nav-item">About</li>
<li className="nav-item">Contact</li>
</ul>
</nav>
);
}
.nav {
padding-inline: 1rem;
border-inline-start: 4px solid blue;
}
.nav-list {
display: flex;
gap: 1rem;
margin-block: 0;
padding-inline-start: 0;
}
.nav-item {
margin-inline-end: 1.5rem;
}
Логические свойства для отступов, полей и вставок упрощают и делают более эффективным позиционирование элементов в различных режимах письма. Эти свойства автоматически меняются в контексте RTL без дополнительных стилей или медиазапросов.
4. Используйте логические свойства для позиционирования
Для элементов с абсолютным или относительным позиционированием замените left и right на inset-inline-start и inset-inline-end.
export default function Sidebar() {
return (
<aside className="sidebar">
<button className="close-button">×</button>
<p>Содержимое боковой панели</p>
</aside>
);
}
.sidebar {
position: fixed;
inset-inline-start: 0;
inset-block-start: 0;
inline-size: 250px;
block-size: 100vh;
padding-inline: 1rem;
}
.close-button {
position: absolute;
inset-inline-end: 0.5rem;
inset-block-start: 0.5rem;
}
Свойство ширины заменяется на inline-size, а высота — на block-size в методологии логических свойств. Эти свойства обеспечивают правильное расположение элементов в зависимости от текущего направления текста.
5. Применяйте логическое выравнивание текста
Замените text-align: left и text-align: right на text-align: start и text-align: end.
.content {
text-align: start;
}
.metadata {
text-align: end;
margin-inline-start: auto;
}
Логические свойства относятся к краям блока в зависимости от потока содержимого, а не физических размеров области просмотра. Значения выравнивания текста start и end автоматически адаптируются к направлению текста, корректно выравнивая содержимое как для языков с направлением текста слева направо (LTR), так и справа налево (RTL).