postcss-change-dir v0.1.1
PostCSS RTLCSS 是一个 PostCSS 插件,用于构建包含左到右(LTR)和右到左(RTL)规则的层叠样式表(CSS)。RTLCSS 允许用户翻转整个 CSS 文件,目的是使用原始 CSS 用于一个方向,而新生成的 CSS 用于另一个方向。PostCSS RTLCSS 的作用是创建一个包含两个方向的单一 CSS 文件,或者创建一个仅包含翻转规则的最小 CSS 文件,目的是覆盖主文件。
安装
npm
npm install postcss-change-dir --save-dev
pnpm
pnpm add -D postcss-change-dir
yarn
yarn add postcss-change-dir -D
基本用法
与 CommonJS 一起使用
const postcss = require('postcss');
const postcssRTLCSS = require('postcss-change-dir');
const { Mode, Source } = require('postcss-change-dir/options');
const options = { ...可用选项... };
const result = postcss([
postcssRTLCSS(options)
]).process(cssInput);
const rtlCSS = result.css;
与 ES6 模块一起使用
import postcss from 'postcss';
import postcssRTLCSS from 'postcss-change-dir';
import { Mode, Source } from 'postcss-change-dir/options';
const options = { ...可用选项... };
const result = postcss([
postcssRTLCSS(options)
]).process(cssInput);
const rtlCSS = result.css;
在 Webpack 中与 postcss-loader 一起使用
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [postcssRTLCSS(options)]
}
}
}
]
}
]
示例
输入
.test1,
.test2 {
background-color: #fff;
background-position: 10px 20px;
border-radius: 0 2px 0 8px;
color: #666;
padding-right: 20px;
text-align: left;
transform: translate(-50%, 50%);
width: 100%;
}
.test3 {
direction: ltr;
margin: 1px 2px 3px;
padding: 10px 20px;
text-align: center;
}
使用组合模式(默认推荐)
这是推荐的方法,它将生成更多的 CSS 代码,因为每个方向都将具有其特定的前缀规则,但这是最安全的选择。
.test1,
.test2 {
background-color: #fff;
background-position: 10px 20px;
color: #666;
width: 100%;
}
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
border-radius: 0 2px 0 8px;
padding-right: 20px;
text-align: left;
transform: translate(-50%, 50%);
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
border-radius: 2px 0 8px 0;
padding-left: 20px;
text-align: right;
transform: translate(50%, 50%);
}
.test3 {
margin: 1px 2px 3px;
padding: 10px 20px;
text-align: center;
}
[dir='ltr'] .test3 {
direction: ltr;
}
[dir='rtl'] .test3 {
direction: rtl;
}
使用覆盖模式输出
这是覆盖的另一种替代方法。它将生成较少的代码,因为它让主规则保持不变,并且生成较短的特定规则来覆盖受文本方向影响的属性。
.test1,
.test2 {
background-color: #fff;
background-position: 10px 20px;
border-radius: 0 2px 0 8px;
color: #666;
padding-right: 20px;
text-align: left;
transform: translate(-50%, 50%);
width: 100%;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
border-radius: 2px 0 8px 0;
padding-right: 0;
padding-left: 20px;
text-align: right;
transform: translate(50%, 50%);
}
.test3 {
direction: ltr;
margin: 1px 2px 3px;
padding: 10px 20px;
text-align: center;
}
[dir='rtl'] .test3 {
direction: rtl;
}
使用差异模式输出
这是第二种替代的覆盖方法。它生成的代码量最少,因为它只输出被翻转的规则,而不加前缀。这种方法的目的是生成一个单独的样式表文件,该文件将被加载在原始文件之上,以覆盖需要在特定方向翻转的规则。
.test1,
.test2 {
border-radius: 2px 0 8px 0;
padding-right: 0;
padding-left: 20px;
text-align: right;
transform: translate(50%, 50%);
}
.test3 {
direction: rtl;
}
两种覆盖方法的缺点
- 一些指令如
/*rtl:freeze*/
,/*rtl:begin:freeze*/
和/*rtl:end:freeze*/
在这些方法中不起作用。 - 它们可能会覆盖来自另一个类的属性,如果同时使用多个类。查看下一个
HTML
和CSS
代码:
<div class="test1 test2">这是一个示例</div>
.test1 {
background: #666;
color: #fff;
padding: 20px;
}
.test2 {
padding-right: 10px;
}
使用 combined
方法,生成的代码将是下一个:
.test1 {
background: #666;
color: #fff;
padding: 20px;
}
[dir='ltr'] .test2 {
padding-right: 10px;
}
[dir='rtl'] .test2 {
padding-left: 10px;
}
所以,div
在 LTR
中的 padding 将是 20px 10px 20px 20px
,在 RTL
中将是 20px 20px 20px 10px
。这里一切都按预期工作。
然而,使用 override
方法,生成的代码将是下一个:
.test1 {
background: #666;
color: #fff;
padding: 20px;
}
.test2 {
padding-right: 10px;
}
[dir='rtl'] .test2 {
padding-right: 0;
padding-left: 10px;
}
使用 diff
方法,生成的代码将是下一个:
.test2 {
padding-right: 0;
padding-left: 10px;
}
现在 div
在 LTR
中的 padding 将是 20px 10px 20px 20px
,在 RTL
中将是 20px 0 20px 10px
,因为当类 test2
被覆盖时,没有考虑到它可能与 test1
一起使用,具有相同的属性。在这种情况下的解决方案是提供被继承的属性:
.test1 {
background: #666;
color: #fff;
padding: 20px;
}
.test2 {
padding-left: 20px;
padding-right: 10px;
}
所以,使用 override
方法,生成的代码将是:
.test1 {
background: #666;
color: #fff;
padding: 20px;
}
.test2 {
padding-left: 20px;
padding-right: 10px;
}
[dir='rtl'] .test2 {
padding-right: 20px;
padding-left: 10px;
}
使用 diff
方法,生成的代码将是:
.test2 {
padding-right: 20px;
padding-left: 10px;
}
插件选项
所有选项都是可选的,如果省略了任何一个选项或者它们的类型或格式错误,将使用默认值
选项 | 类型 | 默认值 | 描述 |
---|---|---|---|
mode | Mode (string) | Mode.combined | 生成最终 CSS 规则的模式 |
ltrPrefix | string or string[] | [dir="ltr"] | 左到右 CSS 规则中使用的前缀 |
rtlPrefix | string or string[] | [dir="rtl"] | 右到左 CSS 规则中使用的前缀 |
bothPrefix | string or string[] | [dir] | 创建一个新规则,当 ltr 或 rtl 规则的特异性覆盖其声明时,影响两个方向 |
prefixSelectorTransformer | function | null | 转换函数,以更控制选择器前缀逻辑 |
safeBothPrefix | boolean | false | 将 bothPrefix 添加到可能受方向影响的声明中,以避免被特异性覆盖 |
ignorePrefixedRules | boolean | true | 忽略已经被 ltrPrefix , rtlPrefix , 或 bothPrefix 中的一些前缀标记的规则 |
source | Source (string) | Source.ltr | 从哪个方向生成最终 CSS |
processUrls | boolean | false | 使用字符串映射更改 URL 中的字符串 |
processRuleNames | boolean | false | 如果它们与 stringMap 中的任何条目匹配,则在方向变化时交换两个规则,即使它们不包含方向属性 |
processKeyFrames | boolean | false | 翻转关键帧动画 |
processEnv | boolean | true | 当 processEnv 为 false 时,防止翻转代理定义的环境变量(safe-area-inset-left 和 safe-area-inset-right ) |
useCalc | boolean | false | 如果它们使用 calc 表示长度单位,则翻转 background-position-x 和 transform-origin 属性 |
stringMap | PluginStringMap[] | 查看下面 | 用于替换声明的 URL 和匹配规则选择器名称的字符串映射数组,如果 processRuleNames 为 true |
greedy | boolean | false | 当 greedy 为 true 时,stringMap 的匹配不考虑单词边界 |
aliases | Record<string, string> | {} | 字符串映射,将一些声明视为其他声明 |
processDeclarationPlugins | DeclarationPlugin[] | [] | 处理 CSS 声明时应用的插件 |
mode
mode 选项已在 使用组合模式输出, 使用覆盖模式输出, 和 使用差异模式输出 部分中解释。为了避免使用魔术字符串,该包暴露了一个具有这些值的对象,但无论如何都可以使用字符串值:
import postcss from 'postcss'
import postcssRTLCSS from 'postcss-change-dir'
import { Mode } from 'postcss-change-dir/options'
const input = '... css 代码 ...'
const optionsCombined = { mode: Mode.combined } // 这是默认值
const optionsOverride = { mode: Mode.override }
const optionsDiff = { mode: Mode.diff }
const outputCombined = postcss([postcssRTLCSS(optionsCombined)]).process(input)
const outputOverride = postcss([postcssRTLCSS(optionsOverride)]).process(input)
const outputDiff = postcss([postcssRTLCSS(optionsDiff)]).process(input)
ltrPrefix 和 rtlPrefix
这两个选项管理每个方向的前缀字符串。它们可以是字符串或字符串数组:
输入
.test1,
.test2 {
left: 10px;
}
.test3,
.test4 {
text-align: left;
}
使用字符串
const options = {
ltrPrefix: '.ltr',
rtlPrefix: '.rtl'
}
输出
.ltr .test1,
.ltr .test2 {
left: 10px;
}
.rtl .test1,
.rtl .test2 {
right: 10px;
}
.ltr .test3,
.ltr .test4 {
text-align: left;
}
.rtl .test3,
.rtl .test4 {
text-align: right;
}
使用字符串数组
const options = {
ltrPrefix: ['[dir="ltr"]', '.ltr'],
rtlPrefix: ['[dir="rtl"]', '.rtl']
}
输出
[dir='ltr'] .test1,
.ltr .test1,
[dir='ltr'] .test2,
.ltr .test2 {
left: 10px;
}
[dir='rtl'] .test1,
.rtl .test1,
[dir='rtl'] .test2,
.rtl .test2 {
right: 10px;
}
[dir='ltr'] .test3,
.ltr .test3,
[dir='ltr'] .test4,
.ltr .test4 {
text-align: left;
}
[dir='rtl'] .test3,
.rtl .test3,
[dir='rtl'] .test4,
.rtl .test4 {
text-align: right;
}
bothPrefix
这个前缀将在一些特定情况下使用,其中一个 ltr 或 rtl 规则将由于特异性覆盖主规则中位于的声明。考虑使用 processUrls
选项作为 true
的下一个示例:
.test1 {
background: url('icons/ltr/arrow.png');
background-size: 10px 20px;
width: 10px;
}
生成的 CSS 将是:
.test1 {
background-size: 10px 20px;
width: 10px;
}
[dir='ltr'] .test1 {
background: url('icons/ltr/arrow.png');
}
[dir='rtl'] .test1 {
background: url('icons/rtl/arrow.png');
}
在之前的案例中,background-size
属性被 background
属性覆盖。即使我们改变规则的顺序,最后一组规则具有更高的特异性,因此它们将覆盖第一组规则。
为了解决这个问题,最后将使用 bothPrefix
参数创建另一个规则:
.test1 {
width: 10px;
}
[dir='ltr'] .test1 {
background: url('icons/ltr/arrow.png');
}
[dir='rtl'] .test1 {
background: url('icons/rtl/arrow.png');
}
[dir] {
background-size: 10px 20px;
}
不管怎样的方向,background-size
属性都受到尊重。
prefixSelectorTransformer
这个函数将用于转换选择器,并根据我们的意愿前缀它们。第一个参数将是使用的前缀,第二个是当前选择器:
- 如果该函数不返回字符串,则将使用默认的前缀逻辑。
- 如果使用这个函数,请确保
html
,:root
或::view-transition
使用自定义前缀逻辑。您应该涵盖这些情况。
输入
.test1 {
left: 10px;
padding-right: 5px;
padding-inline-end: 20px;
}
如果 prefixSelectorTransformer
没有发送(默认):
输出
[dir='ltr'] .test1 {
left: 10px;
padding-right: 5px;
}
[dir='rtl'] .test1 {
right: 10px;
padding-left: 5px;
}
[dir] .test1 {
padding-inline-end: 20px;
}
设置 prefixSelectorTransformer
函数
const options = {
prefixSelectorTransformer: function (prefix, selector) {
if (prefix === '[dir]') {
return `.container > ${prefix} > ${selector}`
}
return `${selector}${prefix}`
}
}
输出
.test1[dir='ltr'] {
left: 10px;
padding-right: 5px;
}
.test1[dir='rtl'] {
right: 10px;
padding-left: 5px;
}
.container > [dir] > .test1 {
padding-inline-end: 20px;
}
safeBothPrefix
这个选项将 boxPrefix
选项添加到可以翻转的声明中,不管它们是否在同一规则中被覆盖。这避免了它们被其他规则中包含的翻转声明的特异性覆盖。例如,让我们考虑一个 div
元素具有以下规则:
<div class="test1 test2">这是一个示例</div>
.test1 {
color: #fff;
padding: 4px 10px 4px 20px;
width: 100%;
}
.test2 {
padding: 0;
}
预期的结果是元素的 padding
变为 0
,因为它被 test2
重置了。使用 safeBothPrefix
为 false
时,生成的 CSS 将是:
.test1 {
color: #fff;
width: 100%;
}
[dir='ltr'] .test1 {
padding: 4px 10px 4px 20px;
}
[dir='rtl'] .test1 {
padding: 4px 20px 4px 10px;
}
.test2 {
padding: 0;
}
结果是 test1
的 padding
属性的特异性高于 test2
中的同一属性,所以如果同时应用两个规则,则不会被重置。让我们检查如果 safeBothPrefix
是 true
的结果:
.test1 {
color: #fff;
width: 100%;
}
[dir='ltr'] .test1 {
padding: 4px 10px 4px 20px;
}
[dir='rtl'] .test1 {
padding: 4px 20px 4px 10px;
}
[dir] .test2 {
padding: 0;
}
由于 test2
具有与 test1
相同的特异性水平,现在结果是如果同时使用两个规则,则 padding
将被重置。
ignorePrefixedRules
这个选项用于忽略已经被 ltrPrefix
, rtlPrefix
, 或 bothPrefix
中的一些前缀标记的规则:
输入
[dir='ltr'] test {
left: 10px;
}
[dir='rtl'] test {
right: 10px;
}
ignorePrefixedRules 为 true
const options = { ignorePrefixedRules: true } // 这是默认值
输出
[dir='ltr'] test {
left: 10px;
}
[dir='rtl'] test {
right: 10px;
}
ignorePrefixedRules 为 false
const options = { ignorePrefixedRules: false }
输出
[dir='ltr'] [dir='ltr'] test {
left: 10px;
}
[dir='rtl'] [dir='ltr'] test {
right: 10px;
}
[dir='ltr'] [dir='rtl'] test {
right: 10px;
}
[dir='rtl'] [dir='rtl'] test {
left: 10px;
}
source
这个选项管理转换是从 LTR
到 RTL
还是反之。
输入
.test1,
.test2 {
left: 10px;
}
使用 Source.ltr 在组合模式
import { Mode, Source } from 'postcss-change-dir/options'
const options = {
mode: Mode.combined,
source: Source.ltr // 这是默认值
}
输出
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
left: 10px;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
right: 10px;
}
使用 Source.rtl 在覆盖模式
import { Mode, Source } from 'postcss-change-dir/options'
const options = {
mode: Mode.override,
source: Source.rtl
}
输出
.test1,
.test2 {
left: 10px;
}
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
left: auto;
right: 10px;
}
processUrls
这个选项管理是否应该翻转 URL 中的字符串,考虑到字符串映射:
输入
.test1,
.test2 {
background-image: url('./folder/subfolder/icons/ltr/chevron-left.png');
left: 10px;
}
processUrls 为 false
const options = { processUrls: false } // 这是默认值
输出
.test1,
.test2 {
background-image: url('./folder/subfolder/icons/ltr/chevron-left.png');
}
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
left: 10px;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
right: 10px;
}
processUrls 为 true
const options = { processUrls: true }
输出
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
background-image: url('./folder/subfolder/icons/ltr/chevron-left.png');
left: 10px;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
background-image: url('./folder/subfolder/icons/rtl/chevron-right.png');
right: 10px;
}
processRuleNames
如果为 true
,则在方向变化时,如果它们与 stringMap
中的任何条目匹配,则交换两个不包含方向属性的规则
!重要 这个选项不会前缀已经被处理过的规则,因为它们具有方向属性。
输入
.test1-ltr {
color: #fff;
}
.test2-left::before {
content: '\f007';
}
.test2-right::before {
content: '\f010';
}
processRuleNames 为 true
const options = {
processRuleNames: true
}
输出
/* 这个选择器将不会被处理,因为它没有对应的 */
.test1-ltr {
color: #fff;
}
[dir='ltr'] .test2-left::before {
content: '\f007';
}
[dir='rtl'] .test2-left::before {
content: '\f010';
}
[dir='ltr'] .test2-right::before {
content: '\f010';
}
[dir='rtl'] .test2-right::before {
content: '\f007';
}
processKeyFrames
这个选项管理是否应该翻转 @keyframes 动画规则:
输入
.test1 {
animation: 5s flip 1s ease-in-out;
color: #fff;
}
@keyframes flip {
from {
transform: translateX(100px);
}
to {
transform: translateX(0);
}
}
processKeyFrames 为 false
const options = { processKeyFrames: false } // 这是默认值
输出
.test1 {
animation: 5s flip 1s ease-in-out;
color: #fff;
}
@keyframes flip {
from {
transform: translateX(100px);
}
to {
transform: translateX(0);
}
}
processKeyFrames 为 true
const options = { processKeyFrames: true }
输出
.test1 {
color: #fff;
}
[dir='ltr'] .test1 {
animation: 5s flip-ltr 1s ease-in-out;
}
[dir='rtl'] .test1 {
animation: 5s flip-rtl 1s ease-in-out;
}
@keyframes flip-ltr {
from {
transform: translateX(100px);
}
to {
transform: translateX(0);
}
}
@keyframes flip-rtl {
from {
transform: translateX(-100px);
}
to {
transform: translateX(0);
}
}
processEnv
这个选项管理是否应该翻转代理定义的环境变量:
输入
body {
padding: env(safe-area-inset-top, 10px) env(safe-area-inset-right, 20px) env(safe-area-inset-bottom, 30px) env(
safe-area-inset-left,
40px
);
}
.test1 {
margin-right: env(safe-area-inset-right, 10px);
margin-left: env(safe-area-inset-left, 20px);
}
processEnv 为 true
const options = { processEnv: true } // 这是默认值
输出
[dir='ltr'] body {
padding: env(safe-area-inset-top, 10px) env(safe-area-inset-right, 20px) env(safe-area-inset-bottom, 30px) env(
safe-area-inset-left,
40px
);
}
[dir='rtl'] body {
padding: env(safe-area-inset-top, 10px) env(safe-area-inset-right, 40px) env(safe-area-inset-bottom, 30px) env(
safe-area-inset-left,
20px
);
}
[dir='ltr'] .test1 {
margin-right: env(safe-area-inset-right, 10px);
margin-left: env(safe-area-inset-left, 20px);
}
[dir='rtl'] .test1 {
margin-left: env(safe-area-inset-left, 10px);
margin-right: env(safe-area-inset-right, 20px);
}
processEnv 为 false
const options = { processEnv: false }
输出
[dir='ltr'] body {
padding: env(safe-area-inset-top, 10px) env(safe-area-inset-right, 20px) env(safe-area-inset-bottom, 30px) env(
safe-area-inset-left,
40px
);
}
[dir='rtl'] body {
padding: env(safe-area-inset-top, 10px) env(safe-area-inset-left, 40px) env(safe-area-inset-bottom, 30px) env(
safe-area-inset-right,
20px
);
}
[dir='ltr'] .test1 {
margin-right: env(safe-area-inset-right, 10px);
margin-left: env(safe-area-inset-left, 20px);
}
[dir='rtl'] .test1 {
margin-left: env(safe-area-inset-right, 10px);
margin-right: env(safe-area-inset-left, 20px);
}
useCalc
当这个选项启用时,如果它们使用 calc 表示长度单位,则翻转 background-position-x
和 transform-origin
属性:
输入
.test {
background-image: url('./folder/subfolder/icons/ltr/chevron-left.png');
background-position-x: 5px;
left: 10px;
transform-origin: 10px 20px;
transform: scale(0.5, 0.5);
}
useCalc 为 false
const options = { useCalc: false } // 这是默认值
输出
.test {
background-image: url('./folder/subfolder/icons/ltr/chevron-left.png');
background-position-x: 5px;
transform-origin: 10px 20px;
transform: scale(0.5, 0.5);
}
[dir='ltr'] .test {
left: 10px;
}
[dir='rtl'] .test {
right: 10px;
}
useCalc 为 true
const options = { useCalc: true }
输出
.test {
background-image: url('./folder/subfolder/icons/ltr/chevron-left.png');
transform: scale(0.5, 0.5);
}
[dir='ltr'] .test {
background-position-x: 5px;
left: 10px;
transform-origin: 10px 20px;
}
[dir='rtl'] .test {
background-position-x: calc(100% - 5px);
right: 10px;
transform-origin: calc(100% - 10px) 20px;
}
stringMap
一个字符串映射数组,用于替换声明的 URL 和匹配规则选择器名称,如果 processRuleNames
选项为 true
。名称参数是可选的,但如果您想覆盖任何默认字符串映射,只需使用相同的名称添加您自己的。
// 这是默认的字符串映射对象
const options = {
stringMap: [
{
name: 'left-right',
search: ['left', 'Left', 'LEFT'],
replace: ['right', 'Right', 'RIGHT']
},
{
name: 'ltr-rtl',
search: ['ltr', 'Ltr', 'LTR'],
replace: ['rtl', 'Rtl', 'RTL']
}
]
}
greedy
当 greedy
为 true
时,stringMap
的匹配不考虑单词边界。
输入
.test1 {
background: url('icon-left.png');
}
.test2 {
background: url('icon-ultra.png');
}
greedy 为 false
const options = {
processUrls: true,
greedy: false // 这是默认值
}
输出
[dir='ltr'] .test1 {
background: url('icon-left.png');
}
[dir='rtl'] .test1 {
background: url('icon-right.png');
}
.test2 {
background: url('icon-ultra.png');
}
greedy 为 true
const options = {
processUrls: true,
greedy: true
}
输出
[dir='ltr'] .test1 {
background: url('icon-left.png');
}
[dir='rtl'] .test1 {
background: url('icon-right.png');
}
[dir='ltr'] .test2 {
background: url('icon-ultra.png');
}
[dir='rtl'] .test2 {
background: url('icon-urtla.png');
}
aliases
这个属性由字符串映射组成,将一些声明视为其他声明,这对于翻转 CSS 变量 的值非常有用。
输入
:root {
--my-padding: 1rem 1rem 1.5rem 1.5rem;
}
.test {
padding: var(--my-padding);
}
没有别名字符串映射(默认)
输出
:root {
--my-padding: 1rem 1rem 1.5rem 1.5rem;
}
.test {
padding: var(--my-padding);
}
设置别名字符串映射
const options = {
aliases: {
'--my-padding': 'padding'
}
}
输出
[dir='ltr']:root {
--my-padding: 1rem 1rem 1.5rem 1.5rem;
}
[dir='rtl']:root {
--my-padding: 1rem 1.5rem 1.5rem 1rem;
}
.test {
padding: var(--my-padding);
}
processDeclarationPlugins
processDeclarationPlugins 选项的目的是处理声明,以扩展或覆盖 RTLCSS 功能。例如,我们可以避免自动翻转 background-position
。
输入
.test {
background-position: 0 100%;
}
将 0
转换为 100%
(默认)
输出
.test {
background-position: 100% 100%;
}
设置插件以避免翻转
const options = {
processDeclarationPlugins: [
{
name: 'avoid-flipping-background',
priority: 99, // 高于核心 RTLCSS 插件的优先值 100
processors: [
{
expr: /(background|object)(-position(-x)?|-image)?$/i,
action: (prop, value) => ({ prop, value })
}
]
}
]
}
输出
.test {
background-position: 0 100%;
}
控制指令
控制指令放置在规则或声明之间。它们可以针对单个节点或一组节点。
!重要 块指令(以
begin
开始和以end
结束的那些)应该放置在规则外部以应用到多个规则,或放置在规则内部以应用到多个声明。您不应将指令的开始放置在规则外部,将结束放置在内部(或反之),否则将得到不期望的结果。
指令 | 描述 |
---|---|
/*rtl:ignore*/ | 忽略处理以下规则或声明 |
/*rtl:begin:ignore*/ | 开始忽略块 |
/*rtl:end:ignore*/ | 结束忽略块 |
/*rtl:freeze*/ | 在当前方向冻结规则或声明 |
/*rtl:begin:freeze*/ | 开始冻结块 |
/*rtl:end:freeze*/ | 结束冻结块 |
/*rtl:urls*/ | 此指令在下一个声明或下一个规则的声明中将 processUrls 选项设置为 true ,不管全局 processUrls 选项的值如何 |
/*rtl:begin:urls*/ | 开始 processUrls 块 |
/*rtl:end:urls*/ | 结束 processUrls 块 |
/*rtl:rules*/ | 此指令在下一个规则中将 processRuleNames 选项设置为 true ,不管全局 processRuleNames 选项的值如何 |
/*rtl:begin:rules*/ | 开始 processRuleNames 块 |
/*rtl:end:rules*/ | 结束 processRuleNames 块 |
/*rtl:source:{source}*/ | 设置规则或声明的源,不管 source 属性的值如何 |
/*rtl:begin:source:{source}*/ | 开始源块 |
/*rtl:end:source*/ | 结束源块 |
/*rtl:raw:{CSS}*/ | 解析 CSS 参数并插入到其位置。根据 source 参数,解析的 CSS 将被视为 rtl 或 ltr |
/*rtl:ignore*/
这个指令忽略了对以下规则或声明的处理。在下一个块中,整个声明将被忽略。
输入
/*rtl:ignore*/
.test1,
.test2 {
text-align: left;
left: 10px;
}
输出
.test1,
.test2 {
text-align: left;
left: 10px;
}
在下一个块中,只有 left
属性将被忽略:
输入
.test3,
.test4 {
text-align: left;
/*rtl:ignore*/
left: 10px;
}
输出
.test3,
.test4 {
left: 10px;
}
[dir='ltr'] .test3,
[dir='ltr'] .test4 {
text-align: left;
}
[dir='rtl'] .test3,
[dir='rtl'] .test4 {
text-align: right;
}
/*rtl:begin:ignore*/ 和 /*rtl:end:ignore*/
这两个指令应该一起使用,它们将提供忽略规则或声明的开始和结束。
!注意 插入在这些块之间的指令将被忽略,并保留在最终输出中。
忽略多个规则:
输入
/*rtl:begin:ignore*/
.test1,
.test2 {
left: 10px;
text-align: left;
}
.test3 {
padding: 1px 2px 3px 4px;
}
/*rtl:end:ignore*/
输出
.test1,
.test2 {
left: 10px;
text-align: left;
}
.test3 {
padding: 1px 2px 3px 4px;
}
忽略多个声明:
输入
.test1,
.test2 {
left: 10px;
/*rtl:begin:ignore*/
margin-left: 4em;
padding: 1px 2px 3px 4px;
/*rtl:end:ignore*/
text-align: left;
}
输出
.test1,
.test2 {
margin-left: 4em;
padding: 1px 2px 3px 4px;
}
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
left: 10px;
text-align: left;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
right: 10px;
text-align: right;
}
/*rtl:freeze*/
!重要 此指令仅在
combined
模式下工作。如果您在override
或diff
模式下使用它,它将被忽略。
这个指令在当前方向冻结规则或声明,但对 counterpart direction 如果有可翻转声明则不采取任何操作。当用于规则时,即使它不包含可翻转声明,也会在当前方向冻结它。当它用于声明时,即使它不可翻转,也会在当前方向冻结该声明。
输入
/*rtl:freeze*/
.test1,
.test2 {
color: red;
text-align: left;
left: 10px;
}
.test3 {
/*rtl:freeze*/
text-align: center;
/*rtl:freeze*/
padding: 10px 20px 30px 40px;
margin: 1px 2px 3px 4px;
}
输出
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
color: red;
text-align: left;
left: 10px;
}
[dir='ltr'] .test3 {
text-align: center;
padding: 10px 40px 30px 20px;
margin: 1px 4px 3px 2px;
}
[dir='rtl'] .test3 {
margin: 1px 4px 3px 2px;
}
/*rtl:begin:freeze*/ 和 /*rtl:end:freeze*/
!重要 此指令仅在
combined
模式下工作。如果您在override
或diff
模式下使用它,它将被忽略。
这两个指令应该一起使用,它们将提供冻结规则或声明的开始和结束。这些块之间的规则或声明,将即使没有涉及可翻转声明,也会在当前方向冻结。
冻结多个规则:
输入
/*rtl:begin:freeze*/
.test1,
.test2 {
color: #fff;
left: 10px;
text-align: left;
}
.test3 {
padding: 1px 2px 3px 4px;
}
/*rtl:end:freeze*/
输出
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
color: #fff;
left: 10px;
text-align: left;
}
[dir='ltr'] .test3 {
padding: 1px 2px 3px 4px;
}
冻结多个声明:
输入
.test1,
.test2 {
color: red;
left: 10px;
/*rtl:begin:freeze*/
margin-left: 4em;
padding: 1px 2px 3px 4px;
/*rtl:end:freeze*/
text-align: left;
}
输出
.test1,
.test2 {
color: red;
}
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
left: 10px;
margin-left: 4em;
padding: 1px 2px 3px 4px;
text-align: left;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
right: 10px;
text-align: right;
}
/*rtl:urls*/
这个指令在下一个声明或下一个规则的声明中将 processUrls
选项设置为 true
,不管全局 processUrls
选项的值如何:
输入
/*rtl:urls*/
.test1 {
background-image: url('/buttons/button-ltr.png');
}
.test2 {
/*rtl:urls*/
background-image: url('/icons/icon-left.png');
}
输出
[dir='ltr'] .test1 {
background-image: url('/buttons/button-ltr.png');
}
[dir='rtl'] .test1 {
background-image: url('/buttons/button-rtl.png');
}
[dir='ltr'] .test2 {
background-image: url('/icons/icon-left.png');
}
[dir='rtl'] .test2 {
background-image: url('/icons/icon-right.png');
}
/*rtl:begin:urls*/ 和 /*rtl:end:urls*/
这两个指令应该一起使用,它们将提供 processUrls
块的开始和结束。
输入
/*rtl:begin:urls*/
.test1 {
background-image: url('/buttons/button-ltr.png');
}
.test2 {
background-image: url('/icons/icon-left.png');
}
/*rtl:end:urls*/
.test3 {
/*rtl:begin:urls*/
background-image: url('/images/background-left.png');
cursor: url('/images/cursor-ltr.png');
/*rtl:end:urls*/
}
输出
[dir='ltr'] .test1 {
background-image: url('/buttons/button-ltr.png');
}
[dir='rtl'] .test1 {
background-image: url('/buttons/button-rtl.png');
}
[dir='ltr'] .test2 {
background-image: url('/icons/icon-left.png');
}
[dir='rtl'] .test2 {
background-image: url('/icons/icon-right.png');
}
[dir='ltr'] .test3 {
background-image: url('/images/background-left.png');
cursor: url('/images/cursor-ltr.png');
}
[dir='rtl'] .test3 {
background-image: url('/images/background-right.png');
cursor: url('/images/cursor-rtl.png');
}
/*rtl:rules*/
这个指令在下一个规则中将 processRuleNames
选项设置为 true
,不管全局 processRuleNames
选项的值如何:
输入
/*rtl:rules*/
.test1-ltr {
background-image: url('/images/test1-l.png');
}
/*rtl:rules*/
.test1-rtl {
background-image: url('/images/test1-r.png');
}
/*rtl:rules*/
.test2-left::before {
content: '\f007';
}
.test2-right::before {
content: '\f010';
}
输出
[dir='ltr'] .test1-ltr {
background-image: url('/images/test1-l.png');
}
[dir='rtl'] .test1-ltr {
background-image: url('/images/test1-r.png');
}
[dir='ltr'] .test1-rtl {
background-image: url('/images/test1-r.png');
}
[dir='rtl'] .test1-rtl {
background-image: url('/images/test1-l.png');
}
/* 这些选择器将不会被处理,因为只有其中一个有 rtl:rules 指令 */
.test2-left::before {
content: '\f007';
}
.test2-right::before {
content: '\f010';
}
/*rtl:begin:rules*/ 和 /*rtl:end:rules*/
这两个指令应该一起使用,它们将提供 processRuleNames
块的开始和结束。
输入
.test1-ltr {
background-image: url('/images/test1-l.png');
}
.test1-rtl {
background-image: url('/images/test1-r.png');
}
/*rtl:begin:rules*/
.test2-left::before {
content: '\f007';
}
.test2-right::before {
content: '\f010';
}
/*rtl:end:rules*/
输出
.test1-ltr {
background-image: url('/images/test1-l.png');
}
.test1-rtl {
background-image: url('/images/test1-r.png');
}
[dir='ltr'] .test2-left::before {
content: '\f007';
}
[dir='rtl'] .test2-left::before {
content: '\f010';
}
[dir='ltr'] .test2-right::before {
content: '\f010';
}
[dir='rtl'] .test2-right::before {
content: '\f007';
}
/*rtl:source:{source}*/
这个指令设置规则或指令的源,忽略 source
属性的值:
输入
/*rtl:source:rtl*/
.test {
color: #fff;
border-left: 1px solid #666;
padding: 10px 5px 10px 20px;
text-align: left;
width: 100%;
}
输出
.test {
color: #fff;
width: 100%;
}
[dir='ltr'] .test {
border-right: 1px solid #666;
padding: 10px 20px 10px 5px;
text-align: right;
}
[dir='rtl'] .test {
border-left: 1px solid #666;
padding: 10px 5px 10px 20px;
text-align: left;
}
/*rtl:begin:source:{source}*/ 和 /*rtl:end:source*/
这两个指令应该一起使用,它们将提供规则或声明的源块的开始和结束:
输入
.test {
color: #fff;
border-left: 1px solid #666;
/*rtl:begin:source:rtl*/
padding: 10px 5px 10px 20px;
text-align: left;
/*rtl:end:source*/
width: 100%;
}
输出
.test {
color: #fff;
width: 100%;
}
[dir='ltr'] .test {
border-left: 1px solid #666;
padding: 10px 20px 10px 5px;
text-align: right;
}
[dir='rtl'] .test {
border-right: 1px solid #666;
padding: 10px 5px 10px 20px;
text-align: left;
}
/*rtl:raw:{CSS}*/
解析 CSS
参数并插入到其位置。根据 source
参数,解析的 CSS 将被视为 rtl
或 ltr
:
输入
.test1 {
color: #efefef;
left: 10px;
/*rtl:raw:
height: 50px;
width: 100px;*/
}
/*rtl:raw:.test2 {
color: #EFEFEF;
left: 10px;
width: 100%;
}
.test3 {
transform: translate(10px, 20px);
}
*/
输出
.test1 {
color: #efefef;
}
[dir='ltr'] .test1 {
left: 10px;
}
[dir='rtl'] .test1 {
right: 10px;
height: 50px;
width: 100px;
}
[dir='rtl'] .test2 {
color: #efefef;
left: 10px;
width: 100%;
}
[dir='rtl'] .test3 {
transform: translate(10px, 20px);
}
值指令
值指令放置在声明值内的任何位置。它们针对包含的声明节点。
指令 | 描述 |
---|---|
/*rtl:ignore*/ | 忽略处理当前声明 |
/*rtl:append{value}*/ | 将 {value} 追加到声明值的末尾 |
/*rtl:insert:{value}*/ | 将 {value} 插入到指令所在位置 |
/*rtl:prepend:{value}*/ | 将 {value} 预置到声明值的开头 |
/*rtl:{value}*/ | 用 {value} 替换声明值 |
/*rtl:ignore*/
这个指令忽略了对当前声明的处理:
输入
.test1,
.test2 {
text-align: left /*rtl:ignore*/;
left: 10px;
}
输出
.test1,
.test2 {
text-align: left;
}
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
left: 10px;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
right: 10px;
}
/*rtl:append{value}*/
这个指令将 {value}
追加到声明值的末尾:
输入
.test1,
.test2 {
padding: 10px /*rtl:append20px*/;
left: 10px;
}
输出
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
padding: 10px;
left: 10px;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
padding: 10px 20px;
right: 10px;
}
/*rtl:insert:{value}*/
这个指令将 {value}
插入到指令所在位置的声明值内:
输入
.test1,
.test2 {
padding: 10px /*rtl:insert 20px*/ 5px;
left: 10px;
}
输出
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
padding: 10px 5px;
left: 10px;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
padding: 10px 20px 5px;
right: 10px;
}
/*rtl:prepend:{value}*/
这个指令将 {value}
预置到声明值的开头:
输入
.test1,
.test2 {
font-family:
Arial,
Helvetica /*rtl:prepend:"Droid Arabic Kufi", */;
left: 10px;
}
输出
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
font-family: Arial, Helvetica;
left: 10px;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
font-family: 'Droid Arabic Kufi', Arial, Helvetica;
right: 10px;
}
/*rtl:{value}*/
这个指令用 {value}
替换声明值:
输入
.test1,
.test2 {
font-family:
Arial,
Helvetica /*rtl:"Droid Arabic Kufi"*/;
left: 10px;
}
输出
[dir='ltr'] .test1,
[dir='ltr'] .test2 {
font-family: Arial, Helvetica;
left: 10px;
}
[dir='rtl'] .test1,
[dir='rtl'] .test2 {
font-family: 'Droid Arabic Kufi';
right: 10px;
}
如果您不使用 PostCSS,请根据官方文档添加它并在此设置中配置此插件。