Эффективное развитие и поддержка широкомасштабного CSS для многоязычных сайтов
Рассмотрим этот сценарий: вы разрабатываете многоязычное веб-приложение. Если все языки, на которые вы ориентируетесь, являются либо LTR
, либо RTL
, вам не нужны правила CSS для языка. Однако, если ваши целевые языки представляют собой сочетание языков LTR
и RTL
, вам необходимо указать направление чтения страницы для каждого языка.
Если вы добавите dir='ltr'
или dir='rtl'
в элемент <body>
, вы логически должны ожидать, что он должен сделать необходимую магию.
Однако вам действительно нужно переключить все настройки right
и left
в правилах, таких как text-direction
и margin
. Вам также необходимо изменить правила, такие как margin: 0 10px 0 20px;
на margin: 0 20px 0 10px;
Стандарт W3C мог бы избежать этой проблемы, разрешив еще два значения для правил, связанных с направлением. Другими словами, вместо -right
и -left
(как в margin-right
и margin-left
), они могут допускать следующее:
div.foo { margin-near: 100px; }
/* This would be equivalent to margin-left in LTR, and margin-right in RTL */
div.bar { margin-far: 100px; }
/* This would be equivalent to margin-right in LTR, and margin-left in RTL */
В сущности, во всех правилах/значениях, в которых вы можете в настоящее время ввести слово с привязкой left
или right
, вместо этого вы можете написать near
или far
.
Учитывая текущие недостатки в текущей версии CSS, я ищу некоторые предложения по оптимизации создания и обслуживания двунаправленных больших веб-приложений.
Ответы
Ответ 1
Спустя примерно четыре года после публикации этого вопроса, эта потребность, наконец, будет адресоваться w3. https://drafts.csswg.org/css-logical/
Свойства, которые принимают значения физического направленного ключевого слова (сверху, внизу, влево или вправо) переопределены, чтобы также принять соответствующие поточно-относительные ключевые слова. В таких случаях относительный поток значения могут использоваться вместо соответствующих физических значений. Для свойства, которые принимают несколько ключевых слов, комбинации относительных потоков и физические значения не допускаются (если иное не указано в будущие спецификации).
Ответ 2
Так как вы изменили вопрос на предположение, а не на мысль.
Не совсем логично
Вы заявляете: "Если вы добавляете атрибут dir='rtl'
или dir='ltr'
к элементу <body>
логически, вы ожидаете, что он совершит магию". Магия, по-видимому, заключается в преобразовании: "все right
с left
и все left
с right
в правилах, таких как text-direction
и margin
."
Однако я не согласен с тем, что во всех случаях то, что вы желаете, обязательно является логическим результатом. Существуют примеры использования text-direction
и margin
, которые не обязательно связаны с text-direction
основного сайта. Для margin
это кажется очевидным, так как много раз margin
можно использовать для некоторой формы позиционирования элементов, совершенно не связанных с текстом. То, что text-direction
не будет автоматически переворачиваться, может быть менее очевидным, но все же действительным. Предположим, у кого есть английский (LTR) сайт с цитатой из арабского языка (RTL). Теперь один преобразует основной язык на иврит (RTL), но все еще имеет цитату на арабском языке - это не должно автоматически переходить на LTR, поскольку это было бы неправильно.
Такие вещи, как плавающие элементы, абсолютно позиционированные элементы и т.д. (которые используют значения right
и left
), могут или не могут быть расположены так, как они есть из-за text-direction
.
В основном, это сводится к тому, что, поскольку каждый разрабатывает сайт, который должен быть многоязычным, таким образом, который будет переворачиваться text-direction
, на каждом этапе нужно продумать, что элемент должен делать на основе LTR или RTL.
Что это значит, на мой взгляд, CSS не имеет слабости. Любая слабость заключается в реализации дизайна.
Чистая человеческая мысль в дизайне
Таким образом, хорошим методом было бы выбрать ваше стандартное направление (скажем, LTR), и это будет ваш "базовый" план с прямым CSS.
Затем для элементов, которые вы хотите перевернуть из-за изменения RTL, вы кодируете дополнительный CSS для учета этого путем применения класса к <body>
для таргетинга с помощью или с помощью селектора атрибутов типа body[dir=rtl]
. Затем вы размышляете над каждым элементом, который вы производите, должен ли он быть затронут этим изменением, и если вы добавите css (с дополнительным указателем направления, добавляющим спецификацию для переопределения):
.someClass {
color: red;
margin: 0 10px 0 20px;
float: right;
}
body[dir=rtl] .someClass {
margin: 0 20px 0 10px;
/* kept float as right */
}
.someOtherClass {
border: 1px 10px 1px 1px;
margin: 0 30px 0 50px;
float: left;
}
body[dir=rtl] .someOtherClass {
border: 1px 1px 1px 10px; /* changed border for text */
margin: 0 50px 0 30px;
float: right;
}
Здесь препроцессор, например LESS или SASS (SCSS ) (Дэйв упомянул LESS в своем ответе) может оказаться полезным (см. мое обновление ниже), но это все еще решение, которое требует предусмотрительности.
Если вы не хотите, чтобы код был пронизан избытком CSS
У вас может быть отдельная таблица стилей для RTL css, которая загружается в то время, когда сайт определен в этом конкретном направлении. Возможный недостаток этого заключается в том, что он отделяет "коммутационный" код от исходного кода, поэтому обслуживание может быть более сложным (хорошая документация комментариев об элементах, которые подвергнуты RTL-преобразованию в основном коде, может компенсировать это).
(ОБНОВЛЕНИЕ) Использование LESS для помощи?
Вот мысль о том, чтобы сделать процесс более кратким с помощью препроцессора, такого как LESS. В этом примере используются функции LESS 1.4 (в настоящее время в бета-версии).
Идея 1
- Преимущество: сохраняет все значения, измененные на одно изменение селектора.
- Недостаток: больше работы по кодированию значений в аргументах.
Создайте mixin, чтобы применить желаемый селектор к
.rtl(...) {
//getting the number of arguments
//(weeding out nested commas in parenthesis to do it)
//they are expected to be grouped in pairs of TWO,
//as (property, value, property, value, etc.)
@mainArgs: @arguments;
@numArgs: unit(`"@{mainArgs}".replace(/\([^)]*\)/g,"").split(',').length`);
//keep everything in one selector
body[dir=rtl] & {
//start the loop at 1
.rtlPropLoop(@numArgs);
}
//loop to change all properties
.rtlPropLoop(@total; @index: 1; @prop: extract(@mainArgs, @index); @value: extract(@mainArgs, (@index + 1))) when (@index =< @total) {
//need to define all properties that could be switched
//I've done just four here
.setProp(ML) { //margin left
margin-left: @value;
}
.setProp(MR) { //margin right
margin-right: @value;
}
.setProp(FL) { //float
float: @value;
}
.setProp(TD) { //text direction
text-direction: @value;
}
//... define more possible values to switch
//call setProp
.setProp(@prop);
//continue loop
.rtlPropLoop(@total, (@index + 2));
}
//end loop
.rtlPropLoop(@total, @index) when (@index > @total) {}
}
Затем используйте его по необходимости в других селекторах
.test {
margin: 0 20px 0 10px;
float: right;
.rtl(ML, 20px, MR, 10px, FL, left);
}
.test2 a span {
float: left;
text-direction: rtl;
.rtl(TD, ltr, FL, right);
}
Создание этого готового кода
.test {
margin: 0 20px 0 10px;
float: right;
}
body[dir=rtl] .test {
margin-left: 20px;
margin-right: 10px;
float: left;
}
.test2 a span {
float: left;
text-direction: rtl;
}
body[dir=rtl] .test2 a span {
text-direction: ltr;
float: right;
}
Идея 2
- Преимущество: позволяет использовать синтаксис, аналогичный тому, что вы хотите; может быть легко изменена для работы с LESS 1.3.3.
- Недостаток: создает избыточный вывод css, если в одном селекторе изменяется несколько значений.
Создайте некоторые вспомогательные микшины с синтаксисом, как то, что вы ожидаете в CSS
//define global variable for opposite direction
@oppDir: rtl;
//generic helper mixins used inside other helpers
//to auto flip right/left values
.flipSides(left) {
@newSide: right;
}
.flipSides(right) {
@newSide: left;
}
//specific property helper mixins
.padding-near(@top, @right, @bottom, @left) {
padding: @top @right @bottom @left;
body[[email protected]{oppDir}] & {
padding: @top @left @bottom @right;
}
}
.margin-near(@top, @right, @bottom, @left) {
margin: @top @right @bottom @left;
body[[email protected]{oppDir}] & {
margin: @top @left @bottom @right;
}
}
.float-near(@side) {
float: @side;
.flipSides(@side);
body[[email protected]{oppDir}] & {
float: @newSide;
}
}
Используйте их для определения как ближнего, так и дальнего для каждого направления сразу
.test1 {
.padding-near(10px, 30px, 2px, 40px);
.margin-near(0, 10px, 0, 20px);
.float-near(right);
}
.test2 {
.float-near(left);
}
Создание этого готового кода (повторение примечания .test1
для противоположного направления)
.test1 {
padding: 10px 30px 2px 40px;
margin: 0 10px 0 20px;
float: right;
}
body[dir=rtl] .test1 {
padding: 10px 40px 2px 30px;
}
body[dir=rtl] .test1 {
margin: 0 20px 0 10px;
}
body[dir=rtl] .test1 {
float: left;
}
.test2 {
float: left;
}
body[dir=rtl] .test2 {
float: right;
}
Ответ 3
К сожалению, CSS работает над понятием левого и правого, и это правильное поведение. Есть инструменты, которые помогут вам с переносом CSS из LTR в RTL - тот, который я знаю, это CSS Janus, который будет переворачивать свойства -left/-right и больше.
Ответ 4
Я думаю, что если вы этого хотите, вы должны использовать что-то вроде lesscss.
В работе есть стандарт , но я не знаю о каких-либо браузерах, которые его поддерживают. Даже когда они это делают, скорее всего, он будет сдерживаться поддержкой старого браузера (но когда это не проблема?).
Все технические проблемы в стороне, как только это будет сделано, я предполагаю, что это необходимо реализовать, вам все равно нужно будет вытеснить каждую ссылку влево/вправо, а затем использовать что-то похожее на то, как используются медиа-запросы в отзывчивый дизайн для мобильных браузеров.
Ответ 5
Я использую таблицы стилей Closure, и этот материал так же прост, как флаг командной строки.
Я определяю все как LTR (используя direction:ltr
, где необходимо), а затем используя --output-orientation=RTL
во время компиляции, я получаю сгенерированный CSS-код для меня. Наконец, при определении языкового стандарта (на сервере) я также определяю CSS для ввода в мой шаблон.
Дополнительная информация о LR flipping in Closure находится в https://code.google.com/p/closure-stylesheets/#RTL_Flipping
Ответ 6
Для получения дополнительной информации об одном решении, которое попыталось преодолеть слабость с помощью SASS/LESS, проверьте http://anasnakawa.github.io/bi-app-sass/
Ответ 7
Через три года, задав этот вопрос, знаю, что я вижу тенденцию в использовании словарного логического направления вместо 4-направленных слов.
Логические свойства CSS теперь устраняют эту проблему.
Модель Flex использует ключевые слова start
/end
Теперь Blink поддерживает ключевые слова start/end/before/after
. e.i.
ul, menu, dir {
-webkit-margin-before: 1em;
-webkit-margin-after: 1em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
-webkit-padding-start: 40px;
}