│ ├── bootstrap-grid.css.map
│ ├── bootstrap-grid.min.css
│ ├── bootstrap-grid.min.css.map
- │ ├── bootstrap-grid.rtl.css
- │ ├── bootstrap-grid.rtl.css.map
- │ ├── bootstrap-grid.rtl.min.css
- │ ├── bootstrap-grid.rtl.min.css.map
│ ├── bootstrap-reboot.css
│ ├── bootstrap-reboot.css.map
│ ├── bootstrap-reboot.min.css
│ ├── bootstrap-reboot.min.css.map
- │ ├── bootstrap-reboot.rtl.css
- │ ├── bootstrap-reboot.rtl.css.map
- │ ├── bootstrap-reboot.rtl.min.css
- │ ├── bootstrap-reboot.rtl.min.css.map
│ ├── bootstrap-utilities.css
│ ├── bootstrap-utilities.css.map
│ ├── bootstrap-utilities.min.css
│ ├── bootstrap-utilities.min.css.map
- │ ├── bootstrap-utilities.rtl.css
- │ ├── bootstrap-utilities.rtl.css.map
- │ ├── bootstrap-utilities.rtl.min.css
- │ ├── bootstrap-utilities.rtl.min.css.map
│ ├── bootstrap.css
│ ├── bootstrap.css.map
│ ├── bootstrap.min.css
- │ ├── bootstrap.min.css.map
- │ ├── bootstrap.rtl.css
- │ ├── bootstrap.rtl.css.map
- │ ├── bootstrap.rtl.min.css
- │ └── bootstrap.rtl.min.css.map
+ │ └── bootstrap.min.css.map
└── js/
├── bootstrap.bundle.js
├── bootstrap.bundle.js.map
```
</details>
-We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). [Source maps](https://web.dev/articles/source-maps) (`bootstrap.*.map`) are available for use with certain browsers’ developer tools. Bundled JS files (`bootstrap.bundle.js` and minified `bootstrap.bundle.min.js`) include [Popper](https://popper.js.org/docs/v2/).
+We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). [Source maps](https://web.dev/articles/source-maps) (`bootstrap.*.map`) are available for use with certain browsers' developer tools. Bundled JS files (`bootstrap.bundle.js` and minified `bootstrap.bundle.min.js`) include [Popper](https://popper.js.org/docs/v2/). All CSS files work for both LTR and RTL layouts thanks to logical properties—simply set `dir="rtl"` on your HTML element.
## Bugs and feature requests
file: 'dist/css/bootstrap.min.css',
configPropertyName: 'css_hash'
},
- {
- file: 'dist/css/bootstrap.rtl.min.css',
- configPropertyName: 'css_rtl_hash'
- },
{
file: 'dist/js/bootstrap.min.js',
configPropertyName: 'js_hash'
writeFileSync(outputPath, JSON.stringify(parsed, null, 2))
console.log(`✓ Wrote metadata to ${outputPath}`)
- // Clean up temporary CSS files (including RTL variants that may have been generated)
+ // Clean up temporary CSS files
try {
unlinkSync(cssPath)
} catch {
// File may not exist
}
- // Also clean up any RTL variants that postcss may have created
- const rtlFiles = [
- 'dist/css/utilities-metadata.tmp.rtl.css',
- 'dist/css/utilities-metadata.tmp.rtl.css.map',
- 'dist/css/utilities-metadata.tmp.rtl.min.css',
- 'dist/css/utilities-metadata.tmp.rtl.min.css.map',
+ // Also clean up any other temporary variants that may have been created
+ const tempFiles = [
'dist/css/utilities-metadata.tmp.min.css',
'dist/css/utilities-metadata.tmp.min.css.map'
]
- for (const file of rtlFiles) {
+ for (const file of tempFiles) {
try {
unlinkSync(path.join(rootDir, file))
} catch {
plugins: {
autoprefixer: {
cascade: false
- },
- rtlcss: context.env === 'RTL'
+ }
}
}
}
# See https://www.srihash.org for info on how to generate the hashes
css: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
css_hash: "sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"
- css_rtl: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.rtl.min.css"
- css_rtl_hash: "sha384-CfCrinSRH2IR6a4e6fy2q6ioOX7O6Mtm1L9vRvFZ1trBncWmMePhzvafv7oIcWiW"
js: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.min.js"
js_hash: "sha384-G/EV+4j2dNv+tEPo3++6LCgdCROaejBqfUeNjuKAiuXbjrxilcCdDz6ZAVfHWe1Y"
js_bundle: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
"scripts": {
"start": "npm-run-all --parallel watch docs-serve",
"bundlewatch": "bundlewatch --config .bundlewatch.config.json",
- "css": "npm-run-all css-compile css-prefix css-rtl css-minify css-docs",
+ "css": "npm-run-all css-compile css-prefix css-minify css-docs",
"css-compile": "sass --style expanded --source-map --embed-sources --no-error-css scss/bootstrap.scss:dist/css/bootstrap.css scss/bootstrap-grid.scss:dist/css/bootstrap-grid.css scss/bootstrap-reboot.scss:dist/css/bootstrap-reboot.css scss/bootstrap-utilities.scss:dist/css/bootstrap-utilities.css",
"css-docs": "node build/generate-utilities-json.mjs",
- "css-rtl": "cross-env NODE_ENV=RTL postcss --config build/postcss.config.mjs --dir \"dist/css\" --ext \".rtl.css\" \"dist/css/*.css\" \"!dist/css/*.min.css\" \"!dist/css/*.rtl.css\" \"!dist/css/*.tmp.css\"",
"css-lint": "npm-run-all --aggregate-output --continue-on-error --parallel css-lint-*",
"css-lint-stylelint": "stylelint \"**/*.{css,scss}\" --cache --cache-location .cache/.stylelintcache",
"css-lint-vars": "fusv scss/ site/src/scss/",
"css-minify": "npm-run-all --aggregate-output --parallel css-minify-*",
- "css-minify-main": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/css/ --batch --batch-suffix \".min\" \"dist/css/*.css\" \"!dist/css/*.min.css\" \"!dist/css/*rtl*.css\" \"!dist/css/*.tmp.css\"",
- "css-minify-rtl": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/css/ --batch --batch-suffix \".min\" \"dist/css/*rtl.css\" \"!dist/css/*.min.css\"",
+ "css-minify-main": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/css/ --batch --batch-suffix \".min\" \"dist/css/*.css\" \"!dist/css/*.min.css\" \"!dist/css/*.tmp.css\"",
"css-prefix": "npm-run-all --aggregate-output --parallel css-prefix-*",
- "css-prefix-main": "postcss --config build/postcss.config.mjs --replace \"dist/css/*.css\" \"!dist/css/*.rtl*.css\" \"!dist/css/*.min.css\" \"!dist/css/*.tmp.css\"",
+ "css-prefix-main": "postcss --config build/postcss.config.mjs --replace \"dist/css/*.css\" \"!dist/css/*.min.css\" \"!dist/css/*.tmp.css\"",
"css-prefix-examples": "postcss --config build/postcss.config.mjs --replace \"site/src/assets/examples/**/*.css\"",
- "css-prefix-examples-rtl": "cross-env-shell NODE_ENV=RTL postcss --config build/postcss.config.mjs --dir \"site/src/assets/examples/\" --ext \".rtl.css\" --base \"site/src/assets/examples/\" \"site/src/assets/examples/{blog,carousel,dashboard,cheatsheet}/*.css\" \"!site/src/assets/examples/{blog,carousel,dashboard,cheatsheet}/*.rtl.css\"",
"css-test": "jasmine --config=scss/tests/jasmine.js",
"js": "npm-run-all js-compile js-minify",
"js-compile": "npm-run-all --aggregate-output --parallel js-compile-*",
"netlify": "npm-run-all dist release-sri astro-build",
"watch": "npm-run-all --parallel watch-*",
"watch-css-main": "nodemon --watch scss/ --ext scss --exec \"npm-run-all css-lint css-compile css-prefix\"",
- "watch-css-dist": "nodemon --watch dist/css/ --ext css --ignore \"dist/css/*.rtl.*\" --exec \"npm run css-rtl\"",
"watch-css-docs": "nodemon --watch site/src/scss/ --ext scss --exec \"npm run css-lint\"",
"watch-css-test": "nodemon --watch scss/ --ext scss,js --exec \"npm run css-test\"",
"watch-js-main": "nodemon --watch js/src/ --ext js --exec \"npm-run-all js-lint js-compile\"",
"remark-html": "^16.0.1",
"rollup": "^4.53.2",
"rollup-plugin-istanbul": "^5.0.0",
- "rtlcss": "^4.3.0",
"sass": "^1.90.0",
"sass-true": "^9.0.0",
"shelljs": "^0.10.0",
float: inline-start; // Suppress inline spacings and underlining of the separator
padding-inline-end: var(--#{$prefix}breadcrumb-item-padding-x);
color: var(--#{$prefix}breadcrumb-divider-color);
- content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"};
+ content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider));
}
}
+ [dir="rtl"] &:not(:first-child)::before {
+ content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped));
+ }
+
&.active {
color: var(--#{$prefix}breadcrumb-item-active-color);
}
}
.carousel-control-prev-icon {
- background-image: escape-svg($carousel-control-prev-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-next-icon-bg) + "*/"};
+ background-image: escape-svg($carousel-control-prev-icon-bg);
}
+
+ [dir="rtl"] .carousel-control-prev-icon {
+ background-image: escape-svg($carousel-control-next-icon-bg);
+ }
+
.carousel-control-next-icon {
- background-image: escape-svg($carousel-control-next-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-prev-icon-bg) + "*/"};
+ background-image: escape-svg($carousel-control-next-icon-bg);
+ }
+
+ [dir="rtl"] .carousel-control-next-icon {
+ background-image: escape-svg($carousel-control-prev-icon-bg);
}
// Optional indicator pips/controls
}
}
- /* rtl:begin:ignore */
.bs-popover-end {
> .popover-arrow {
left: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width));
}
}
- /* rtl:end:ignore */
-
.bs-popover-bottom {
> .popover-arrow {
top: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width));
}
}
- /* rtl:begin:ignore */
.bs-popover-start {
> .popover-arrow {
right: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width));
}
}
- /* rtl:end:ignore */
-
.bs-popover-auto {
&[data-popper-placement^="top"] {
@extend .bs-popover-top;
// scss-docs-start spinner-border-keyframes
@keyframes spinner-border {
- to { transform: rotate(360deg) #{"/* rtl:ignore */"}; }
+ to { transform: rotate(360deg); }
}
// scss-docs-end spinner-border-keyframes
}
}
- /* rtl:begin:ignore */
.bs-tooltip-end .tooltip-arrow {
left: calc(-1 * var(--#{$prefix}tooltip-arrow-height));
width: var(--#{$prefix}tooltip-arrow-height);
}
}
- /* rtl:end:ignore */
-
.bs-tooltip-bottom .tooltip-arrow {
top: calc(-1 * var(--#{$prefix}tooltip-arrow-height));
}
}
- /* rtl:begin:ignore */
.bs-tooltip-start .tooltip-arrow {
right: calc(-1 * var(--#{$prefix}tooltip-arrow-height));
width: var(--#{$prefix}tooltip-arrow-height);
}
}
- /* rtl:end:ignore */
-
.bs-tooltip-auto {
&[data-popper-placement^="top"] {
@extend .bs-tooltip-top;
}
}
- // 1. A few input types should stay LTR
+ // A few input types should stay LTR regardless of document direction
// See https://rtlstyling.com/posts/rtl-styling#form-inputs
- // 2. RTL only output
- // See https://rtlcss.com/learn/usage-guide/control-directives/#raw
- /* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
- */
// Remove the inner padding in Chrome and Safari on macOS.
---
export const title = 'قالب المدونة'
export const direction = 'rtl'
-export const extra_css = ['https://fonts.googleapis.com/css?family=Amiri:wght@400;700&display=swap', '../blog/blog.rtl.css']
+export const extra_css = ['https://fonts.googleapis.com/css?family=Amiri:wght@400;700&display=swap', '../blog/blog.css']
import Placeholder from "@shortcodes/Placeholder.astro"
---
/* stylelint-disable @stylistic/selector-list-comma-newline-after */
.blog-header-logo {
- font-family: "Playfair Display", Georgia, "Times New Roman", serif/*rtl:Amiri, Georgia, "Times New Roman", serif*/;
+ font-family: "Playfair Display", Georgia, "Times New Roman", serif;
font-size: 2.25rem;
}
+[dir="rtl"] .blog-header-logo {
+ font-family: Amiri, Georgia, "Times New Roman", serif;
+}
+
.blog-header-logo:hover {
text-decoration: none;
}
h1, h2, h3, h4, h5, h6 {
- font-family: "Playfair Display", Georgia, "Times New Roman", serif/*rtl:Amiri, Georgia, "Times New Roman", serif*/;
+ font-family: "Playfair Display", Georgia, "Times New Roman", serif;
+}
+
+[dir="rtl"] h1,
+[dir="rtl"] h2,
+[dir="rtl"] h3,
+[dir="rtl"] h4,
+[dir="rtl"] h5,
+[dir="rtl"] h6 {
+ font-family: Amiri, Georgia, "Times New Roman", serif;
}
.flex-auto {
+++ /dev/null
-/* stylelint-disable @stylistic/selector-list-comma-newline-after */
-
-.blog-header-logo {
- font-family: Amiri, Georgia, "Times New Roman", serif;
- font-size: 2.25rem;
-}
-
-.blog-header-logo:hover {
- text-decoration: none;
-}
-
-h1, h2, h3, h4, h5, h6 {
- font-family: Amiri, Georgia, "Times New Roman", serif;
-}
-
-.flex-auto {
- flex: 0 0 auto;
-}
-
-.h-250 { height: 250px; }
-@media (min-width: 768px) {
- .h-md-250 { height: 250px; }
-}
-
-/* Pagination */
-.blog-pagination {
- margin-bottom: 4rem;
-}
-
-/*
- * Blog posts
- */
-.blog-post {
- margin-bottom: 4rem;
-}
-.blog-post-meta {
- margin-bottom: 1.25rem;
- color: #727272;
-}
---
export const title = 'قالب شرائح العرض'
export const direction = 'rtl'
-export const extra_css = ['../carousel/carousel.rtl.css']
+export const extra_css = ['../carousel/carousel.css']
import Placeholder from "@shortcodes/Placeholder.astro"
---
+++ /dev/null
-/* GLOBAL STYLES
--------------------------------------------------- */
-/* Padding below the footer and lighter body text */
-
-body {
- padding-top: 3rem;
- padding-bottom: 3rem;
- color: rgb(var(--bs-tertiary-color-rgb));
-}
-
-
-/* CUSTOMIZE THE CAROUSEL
--------------------------------------------------- */
-
-/* Carousel base class */
-.carousel {
- margin-bottom: 4rem;
-}
-/* Since positioning the image, we need to help out the caption */
-.carousel-caption {
- bottom: 3rem;
- z-index: 10;
-}
-
-/* Declare heights because of positioning of img element */
-.carousel-item {
- height: 32rem;
-}
-
-
-/* MARKETING CONTENT
--------------------------------------------------- */
-
-/* Center align the text within the three columns below the carousel */
-.marketing .col-lg-4 {
- margin-bottom: 1.5rem;
- text-align: center;
-}
-.marketing .col-lg-4 p {
- margin-right: .75rem;
- margin-left: .75rem;
-}
-
-
-/* Featurettes
-------------------------- */
-
-.featurette-divider {
- margin: 5rem 0; /* Space out the Bootstrap <hr> more */
-}
-
-/* Thin out the marketing headings */
-
-/* RESPONSIVE CSS
--------------------------------------------------- */
-
-@media (min-width: 40em) {
- /* Bump up size of carousel content */
- .carousel-caption p {
- margin-bottom: 1.25rem;
- font-size: 1.25rem;
- line-height: 1.4;
- }
-
- .featurette-heading {
- font-size: 50px;
- }
-}
-
-@media (min-width: 62em) {
- .featurette-heading {
- margin-top: 7rem;
- }
-}
import Example from '@shortcodes/Example.astro'
export const title = 'ورقة الغش'
-export const extra_css = ['../cheatsheet/cheatsheet.rtl.css']
+export const extra_css = ['../cheatsheet/cheatsheet.css']
export const extra_js = [{src: '../cheatsheet/cheatsheet.js'}]
export const body_class = 'bg-body-tertiary'
export const direction = 'rtl'
+++ /dev/null
-body {
- scroll-behavior: smooth;
-}
-
-/**
- * Bootstrap "Journal code" icon
- * @link https://icons.getbootstrap.com/icons/journal-code/
- */
-.bd-heading a::before {
- display: inline-block;
- width: 1em;
- height: 1em;
- margin-left: .25rem;
- content: "";
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23999' viewBox='0 0 16 16'%3E%3Cpath d='M4 1h8a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2h1a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1H2a2 2 0 0 1 2-2z'/%3E%3Cpath d='M2 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H2zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H2zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H2z'/%3E%3Cpath fill-rule='evenodd' d='M8.646 5.646a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L10.293 8 8.646 6.354a.5.5 0 0 1 0-.708zm-1.292 0a.5.5 0 0 0-.708 0l-2 2a.5.5 0 0 0 0 .708l2 2a.5.5 0 0 0 .708-.708L5.707 8l1.647-1.646a.5.5 0 0 0 0-.708z'/%3E%3C/svg%3E");
- background-size: 1em;
-}
-
-/* stylelint-disable-next-line selector-max-universal */
-.bd-heading + div > * + * {
- margin-top: 3rem;
-}
-
-/* Table of contents */
-.bd-aside a {
- padding: .1875rem .5rem;
- margin-top: .125rem;
- margin-right: .3125rem;
- color: var(--bs-body-color);
-}
-
-.bd-aside a:hover,
-.bd-aside a:focus {
- color: var(--bs-body-color);
- background-color: rgba(121, 82, 179, .1);
-}
-
-.bd-aside .active {
- font-weight: 600;
- color: var(--bs-body-color);
-}
-
-.bd-aside .btn {
- padding: .25rem .5rem;
- font-weight: 600;
- color: var(--bs-body-color);
-}
-
-.bd-aside .btn:hover,
-.bd-aside .btn:focus {
- color: var(--bs-body-color);
- background-color: rgba(121, 82, 179, .1);
-}
-
-.bd-aside .btn:focus {
- box-shadow: 0 0 0 1px rgba(121, 82, 179, .7);
-}
-
-.bd-aside .btn::before {
- width: 1.25em;
- line-height: 0;
- content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23ccc' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e");
- transition: transform .35s ease;
- transform: rotate(180deg) translateX(-2px);
- transform-origin: .5em 50%;
-}
-
-.bd-aside .btn[aria-expanded="true"]::before {
- transform: rotate(90deg);
-}
-
-
-/* Examples */
-.scrollspy-example {
- height: 200px;
-}
-
-[id="modal"] .bd-example .btn,
-[id="buttons"] .bd-example .btn,
-[id="tooltips"] .bd-example .btn,
-[id="popovers"] .bd-example .btn,
-[id="dropdowns"] .bd-example .btn-group,
-[id="dropdowns"] .bd-example .dropdown,
-[id="dropdowns"] .bd-example .dropup,
-[id="dropdowns"] .bd-example .dropend,
-[id="dropdowns"] .bd-example .dropstart {
- margin: 0 0 1rem 1rem;
-}
-
-/* Layout */
-@media (min-width: 1200px) {
- body {
- display: grid;
- grid-template-rows: auto;
- grid-template-columns: 1fr 4fr 1fr;
- gap: 1rem;
- }
-
- .bd-header {
- position: fixed;
- top: 0;
- right: 0;
- left: 0;
- z-index: 1030;
- grid-column: 1 / span 3;
- }
-
- .bd-aside,
- .bd-cheatsheet {
- padding-top: 4rem;
- }
-
- /**
- * 1. Too bad only Firefox supports subgrids ATM
- */
- .bd-cheatsheet,
- .bd-cheatsheet section,
- .bd-cheatsheet article {
- display: inherit; /* 1 */
- grid-template-rows: auto;
- grid-template-columns: 1fr 4fr;
- grid-column: 1 / span 2;
- gap: inherit; /* 1 */
- }
-
- .bd-aside {
- grid-area: 1 / 3;
- scroll-margin-top: 4rem;
- }
-
- .bd-cheatsheet section,
- .bd-cheatsheet section > h2 {
- top: 2rem;
- scroll-margin-top: 2rem;
- }
-
- .bd-cheatsheet section > h2::before {
- position: absolute;
- top: 0;
- right: 0;
- bottom: -2rem;
- left: 0;
- z-index: -1;
- content: "";
- }
-
- .bd-cheatsheet article,
- .bd-cheatsheet .bd-heading {
- top: 8rem;
- scroll-margin-top: 8rem;
- }
-
- .bd-cheatsheet .bd-heading {
- z-index: 1;
- }
-}
---
export const title = 'قالب لوحة القيادة'
export const direction = 'rtl'
-export const extra_css = ['../dashboard/dashboard.rtl.css']
+export const extra_css = ['../dashboard/dashboard.css']
export const extra_js = [
{ src: 'https://cdn.jsdelivr.net/npm/chart.js@4.3.2/dist/chart.umd.js', integrity: 'sha384-eI7PSr3L1XLISH8JdDII5YN/njoSsxfbrkCTnJrzXt+ENP5MOVBxD+l6sEG4zoLp'},
{ src: 'dashboard.js'}
+++ /dev/null
-.bi {
- display: inline-block;
- width: 1rem;
- height: 1rem;
-}
-
-/*
- * Sidebar
- */
-
-@media (min-width: 768px) {
- .sidebar .offcanvas-lg {
- position: -webkit-sticky;
- position: sticky;
- top: 48px;
- }
- .navbar-search {
- display: block;
- }
-}
-
-.sidebar .nav-link {
- font-size: .875rem;
- font-weight: 500;
-}
-
-.sidebar .nav-link.active {
- color: #2470dc;
-}
-
-.sidebar-heading {
- font-size: .75rem;
-}
-
-/*
- * Navbar
- */
-
-.navbar-brand {
- padding-top: .75rem;
- padding-bottom: .75rem;
- background-color: rgba(0, 0, 0, .25);
- box-shadow: inset 1px 0 0 rgba(0, 0, 0, .25);
-}
-
-.navbar .form-control {
- padding: .75rem 1rem;
-}
│ ├── bootstrap-grid.css.map
│ ├── bootstrap-grid.min.css
│ ├── bootstrap-grid.min.css.map
-│ ├── bootstrap-grid.rtl.css
-│ ├── bootstrap-grid.rtl.css.map
-│ ├── bootstrap-grid.rtl.min.css
-│ ├── bootstrap-grid.rtl.min.css.map
│ ├── bootstrap-reboot.css
│ ├── bootstrap-reboot.css.map
│ ├── bootstrap-reboot.min.css
│ ├── bootstrap-reboot.min.css.map
-│ ├── bootstrap-reboot.rtl.css
-│ ├── bootstrap-reboot.rtl.css.map
-│ ├── bootstrap-reboot.rtl.min.css
-│ ├── bootstrap-reboot.rtl.min.css.map
│ ├── bootstrap-utilities.css
│ ├── bootstrap-utilities.css.map
│ ├── bootstrap-utilities.min.css
│ ├── bootstrap-utilities.min.css.map
-│ ├── bootstrap-utilities.rtl.css
-│ ├── bootstrap-utilities.rtl.css.map
-│ ├── bootstrap-utilities.rtl.min.css
-│ ├── bootstrap-utilities.rtl.min.css.map
│ ├── bootstrap.css
│ ├── bootstrap.css.map
│ ├── bootstrap.min.css
-│ ├── bootstrap.min.css.map
-│ ├── bootstrap.rtl.css
-│ ├── bootstrap.rtl.css.map
-│ ├── bootstrap.rtl.min.css
-│ └── bootstrap.rtl.min.css.map
+│ └── bootstrap.min.css.map
└── js/
├── bootstrap.bundle.js
├── bootstrap.bundle.js.map
└── bootstrap.min.js.map
```
-This is the most basic form of Bootstrap: compiled files for quick drop-in usage in nearly any web project. We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). [Source maps](https://web.dev/articles/source-maps) (`bootstrap.*.map`) are available for use with certain browsers’ developer tools. Bundled JS files (`bootstrap.bundle.js` and minified `bootstrap.bundle.min.js`) include [Popper](https://popper.js.org/docs/v2/).
+This is the most basic form of Bootstrap: compiled files for quick drop-in usage in nearly any web project. We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). [Source maps](https://web.dev/articles/source-maps) (`bootstrap.*.map`) are available for use with certain browsers' developer tools. Bundled JS files (`bootstrap.bundle.js` and minified `bootstrap.bundle.min.js`) include [Popper](https://popper.js.org/docs/v2/). All CSS files work for both LTR and RTL layouts thanks to logical properties—simply set `dir="rtl"` on your HTML element.
### CSS files
<BsTable class="table">
| CSS files | Layout | Content | Components | Utilities |
| --- | --- | --- | --- | --- |
-| `bootstrap.css`<br/> `bootstrap.min.css`<br/> `bootstrap.rtl.css`<br/> `bootstrap.rtl.min.css` | Included | Included | Included | Included |
-| `bootstrap-grid.css`<br/> `bootstrap-grid.rtl.css`<br/> `bootstrap-grid.min.css`<br/> `bootstrap-grid.rtl.min.css` | [Only grid system]([[docsref:/layout/grid]]) | — | — | [Only flex utilities]([[docsref:/utilities/flex]]) |
-| `bootstrap-utilities.css`<br/> `bootstrap-utilities.rtl.css`<br/> `bootstrap-utilities.min.css`<br/> `bootstrap-utilities.rtl.min.css` | — | — | — | Included |
-| `bootstrap-reboot.css`<br/> `bootstrap-reboot.rtl.css`<br/> `bootstrap-reboot.min.css`<br/> `bootstrap-reboot.rtl.min.css` | — | [Only Reboot]([[docsref:/content/reboot]]) | — | — |
+| `bootstrap.css`<br/> `bootstrap.min.css` | Included | Included | Included | Included |
+| `bootstrap-grid.css`<br/> `bootstrap-grid.min.css` | [Only grid system]([[docsref:/layout/grid]]) | — | — | [Only flex utilities]([[docsref:/utilities/flex]]) |
+| `bootstrap-utilities.css`<br/> `bootstrap-utilities.min.css` | — | — | — | Included |
+| `bootstrap-reboot.css`<br/> `bootstrap-reboot.min.css` | — | [Only Reboot]([[docsref:/content/reboot]]) | — | — |
</BsTable>
### JS files
toc: true
---
-## Get familiar
+<Callout type="info">
+ **ProTip:** Get familiar with Bootstrap first with our [getting started guide]([[docsref:/getting-started/introduction]]) before working with RTL.
+</Callout>
-We recommend getting familiar with Bootstrap first by reading through our [Getting Started Introduction page]([[docsref:/getting-started/introduction]]). Once you’ve run through it, continue reading here for how to enable RTL.
+## How it works
-You may also want to read up on [the RTLCSS project](https://rtlcss.com/), as it powers our approach to RTL.
+Bootstrap uses **CSS logical properties** throughout the framework to make RTL support native and automatic. Set `dir="rtl"` and add a `lang` attribute, like `lang="ar"`, on your HTML element and the browser will handle the directional layout changes for you. No separate stylesheets are needed.
-<Callout type="warning">
-**Bootstrap’s RTL feature is still experimental** and will evolve based on user feedback. Spotted something or have an improvement to suggest? [Open an issue]([[config:repo]]/issues/new/choose), we’d love to get your insights.
-</Callout>
+Logical properties are CSS properties that adapt to the writing mode and direction of content. Instead of using physical directions like `left` and `right`, they use logical concepts like `start` and `end`:
-## Required HTML
+- `margin-left` → `margin-inline-start`
+- `margin-right` → `margin-inline-end`
+- `padding-left` → `padding-inline-start`
+- `border-right` → `border-inline-end`
-There are two strict requirements for enabling RTL in Bootstrap-powered pages.
+When you set `dir="rtl"`, these logical properties automatically flip to match the right-to-left layout without requiring any additional CSS transformations. Only HTML changes are required.
-1. Set `dir="rtl"` on the `<html>` element.
-2. Add an appropriate `lang` attribute, like `lang="ar"`, on the `<html>` element.
+### Required HTML
-From there, you’ll need to include an RTL version of our CSS. For example, here’s the stylesheet for our compiled and minified CSS with RTL enabled:
+One line of changes to your HTML is all it takes to enable RTL. Bootstrap will then automatically adapt to the RTL direction using logical properties.
-```html
-<link rel="stylesheet" href="[[config:cdn.css_rtl]]" integrity="[[config:cdn.css_rtl_hash]]" crossorigin="anonymous">
+```diff
+- <html lang="en">
++ <html lang="ar" dir="rtl">
```
+### Live demo
+
+Toggle between LTR and RTL on this page to see Bootstrap's logical properties in action:
+
+<div class="bd-example">
+ <b-checkgroup>
+ <div class="switch">
+ <input type="checkbox" value="" id="rtlSwitch" switch />
+ </div>
+ <label for="rtlSwitch">Enable RTL mode</label>
+ </b-checkgroup>
+</div>
+
+<script>
+{`
+(function() {
+ const rtlSwitch = document.getElementById('rtlSwitch');
+ const htmlElement = document.documentElement;
+
+ // Check current direction on load
+ if (htmlElement.getAttribute('dir') === 'rtl') {
+ rtlSwitch.checked = true;
+ }
+
+ rtlSwitch.addEventListener('change', function() {
+ if (this.checked) {
+ htmlElement.setAttribute('dir', 'rtl');
+ htmlElement.setAttribute('lang', 'ar');
+ } else {
+ htmlElement.setAttribute('dir', 'ltr');
+ htmlElement.setAttribute('lang', 'en');
+ }
+ });
+})();
+`}
+</script>
+
### Starter template
-You can see the above requirements reflected in this modified RTL starter template.
+Here's a modified RTL starter template:
```html
<!doctype html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
- <link rel="stylesheet" href="[[config:cdn.css_rtl]]" integrity="[[config:cdn.css_rtl_hash]]" crossorigin="anonymous">
+ <link rel="stylesheet" href="[[config:cdn.css]]" integrity="[[config:cdn.css_hash]]" crossorigin="anonymous">
<title>مرحبًا بالعالم!</title>
</head>
Get started with one of our several [RTL examples]([[docsref:/examples/#rtl]]).
-## Approach
-
-Our approach to building RTL support into Bootstrap comes with two important decisions that impact how we write and use our CSS:
-
-1. **First, we decided to build it with the [RTLCSS](https://rtlcss.com/) project.** This gives us some powerful features for managing changes and overrides when moving from LTR to RTL. It also allows us to build two versions of Bootstrap from one codebase.
-
-2. **Second, we’ve renamed a handful of directional classes to adopt a logical properties approach.** Most of you have already interacted with logical properties thanks to our flex utilities—they replace direction properties like `left` and `right` in favor `start` and `end`. That makes the class names and values appropriate for LTR and RTL without any overhead.
-
- For example, instead of `.ml-3` for `margin-left`, use `.ms-3`.
-
-Working with RTL, through our source Sass or compiled CSS, shouldn’t be much different from our default LTR though.
-
-## Customize from source
+## Switching directions
-When it comes to [customization]([[docsref:/customize/sass]]), the preferred way is to take advantage of variables, maps, and mixins. This approach works the same for RTL, even if it’s post-processed from the compiled files, thanks to [how RTLCSS works](https://rtlcss.com/learn/getting-started/why-rtlcss/).
-
-### Custom RTL values
-
-Using [RTLCSS value directives](https://rtlcss.com/learn/usage-guide/value-directives/), you can make a variable output a different value for RTL. For example, to decrease the weight for `$font-weight-bold` throughout the codebase, you may use the `/*rtl: {value}*/` syntax:
-
-```scss
-$font-weight-bold: 700 #{/* rtl:600 */} !default;
-```
-
-Which would output to the following for our default CSS and RTL CSS:
-
-```css
-/* bootstrap.css */
-dt {
- font-weight: 700 /* rtl:600 */;
-}
-
-/* bootstrap.rtl.css */
-dt {
- font-weight: 600;
-}
-```
-
-### Alternative font stack
-
-In the case you’re using a custom font, be aware that not all fonts support the non-Latin alphabet. To switch from Pan-European to Arabic family, you may need to use `/*rtl:insert: {value}*/` in your font stack to modify the names of font families.
-
-For example, to switch from `Helvetica Neue` font for LTR to `Helvetica Neue Arabic` for RTL, your Sass code could look like this:
-
-```scss
-$font-family-sans-serif:
- Helvetica Neue #{"/* rtl:insert:Arabic */"},
- // Cross-platform generic font family (default user interface font)
- system-ui,
- // Safari for macOS and iOS (San Francisco)
- -apple-system,
- // Chrome < 56 for macOS (San Francisco)
- BlinkMacSystemFont,
- // Windows
- "Segoe UI",
- // Android
- Roboto,
- // Basic web fallback
- Arial,
- // Linux
- "Noto Sans",
- // Sans serif fallback
- sans-serif,
- // Emoji fonts
- "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;
-```
+**Need both LTR and RTL on the same page?** Wrap your content in containers with different `dir` attributes:
-### LTR and RTL at the same time
-
-Need both LTR and RTL on the same page? Thanks to [RTLCSS String Maps](https://rtlcss.com/learn/usage-guide/string-map/), this is pretty straightforward. Wrap your `@import`s with a class, and set a custom rename rule for RTLCSS:
-
-```scss
-/* rtl:begin:options: {
- "autoRename": true,
- "stringMap":[ {
- "name": "ltr-rtl",
- "priority": 100,
- "search": ["ltr"],
- "replace": ["rtl"],
- "options": {
- "scope": "*",
- "ignoreCase": false
- }
- } ]
-} */
-.ltr {
- @import "../node_modules/bootstrap/scss/bootstrap";
-}
-/*rtl:end:options*/
+```html
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="stylesheet" href="[[config:cdn.css]]" integrity="[[config:cdn.css_hash]]" crossorigin="anonymous">
+ <title>LTR and RTL</title>
+ </head>
+ <body>
+ <!-- LTR content -->
+ <div dir="ltr" lang="en">
+ <h1>This is left-to-right text</h1>
+ <p>Content flows from left to right.</p>
+ </div>
+
+ <!-- RTL content -->
+ <div dir="rtl" lang="ar">
+ <h1>هذا نص من اليمين إلى اليسار</h1>
+ <p>المحتوى يتدفق من اليمين إلى اليسار.</p>
+ </div>
+ </body>
+</html>
```
-After running Sass then RTLCSS, each selector in your CSS files will be prepended by `.ltr`, and `.rtl` for RTL files. Now you’re able to use both files on the same page, and simply use `.ltr` or `.rtl` on your components wrappers to use one or the other direction.
-
-<Callout type="warning">
-**Edge cases and known limitations** to consider when working with a combined LTR and RTL implementation:
-
-1. When switching `.ltr` and `.rtl`, make sure you add `dir` and `lang` attributes accordingly.
-2. Loading both files can be a real performance bottleneck: consider some [optimization]([[docsref:/customize/optimize]]), and maybe try to [load one of those files asynchronously](https://www.filamentgroup.com/lab/load-css-simpler/).
-3. Nesting styles this way will prevent our `form-validation-state()` mixin from working as intended, thus require you tweak it a bit by yourself. [See #31223](https://github.com/twbs/bootstrap/issues/31223).
-</Callout>
-
-Do you want to automate this process and address several edge cases involving both directions within a single stylesheet? Then, consider using [PostCSS RTLCSS](https://github.com/elchininet/postcss-rtlcss) as a [PostCSS](https://github.com/postcss/postcss) plugin to process your source files. PostCSS RTLCSS uses [RTLCSS](https://rtlcss.com) behind the scenes to manage the direction flipping process, but it separates the flipped declarations into rules with a different prefix for LTR and RTL, something that allows you to have both directions within the same stylesheet file. By doing this, you can switch between LTR and RTL orientations by simply changing the `dir` of the page (or even by modifying a specific class if you configure the plugin accordingly).
-
-<Callout type="warning">
-**Important things to take into account** when using PostCSS RTLCSS to build a combined LTR and RTL implementation:
-
-1. It is recommended that you add the `dir` attribute to the `html` element. This way, the entire page will be affected when you change the direction. Also, make sure you add the `lang` attribute accordingly.
-2. Having a single bundle with both directions will increase the size of the final stylesheet (on average, by 20%-30%): consider some [optimization]([[docsref:/customize/optimize]]).
-3. Take into account that PostCSS RTLCSS is not compatible with `/* rtl:remove */` directives because it doesn’t remove any CSS rule. You should replace your `/* rtl:remove */`, `/* rtl:begin:remove */` and `/* rtl:end:remove */` directives with `/* rtl:freeze */`, `/* rtl:begin:freeze */` and `/* rtl:end:freeze */` directives respectively. These directives will prefix the targeted rules or declarations with the current direction but will not create an RTL counterpart (same result as the `remove` ones in RTLCSS).
-</Callout>
-
-## The breadcrumb case
-
-The [breadcrumb separator]([[docsref:/components/breadcrumb]]#dividers) is the only case requiring its own brand-new variable— namely `$breadcrumb-divider-flipped` —defaulting to `$breadcrumb-divider`.
-
## Additional resources
-- [RTLCSS](https://rtlcss.com/)
+- [MDN: CSS Logical Properties and Values](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties)
+- [CSS Logical Properties - web.dev](https://web.dev/learn/css/logical-properties/)
- [RTL Styling 101](https://rtlstyling.com/posts/rtl-styling)
export function getVersionedBsCssProps(direction: 'rtl' | undefined) {
let bsCssLinkHref = '/dist/css/bootstrap'
- if (direction === 'rtl') {
- bsCssLinkHref = `${bsCssLinkHref}.rtl`
- }
-
if (import.meta.env.PROD) {
bsCssLinkHref = `${bsCssLinkHref}.min`
}
}
if (import.meta.env.PROD) {
- bsCssLinkProps.integrity = direction === 'rtl' ? getConfig().cdn.css_rtl_hash : getConfig().cdn.css_hash
+ bsCssLinkProps.integrity = getConfig().cdn.css_hash
}
return bsCssLinkProps
blog: z.string().url(),
cdn: z.object({
css: z.string().url(),
- css_rtl: z.string().url(),
css_hash: z.string(),
- css_rtl_hash: z.string(),
js: z.string().url(),
js_hash: z.string(),
js_bundle: z.string().url(),