Как поддерживать языки с направлением текста справа налево (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).