Arabic text getting cut off in CSS
Find why Arabic letters, line endings or diacritics are clipped, then fix the CSS box, font and truncation rule that hides them.
By Omran Khleifat, Founder of Ritla
Guide14 min read
The word is in the DOM. You can select it, copy it and hear a screen reader announce it. On screen, its last letters or vowel marks have gone missing. CSS has kept the data and removed the evidence.
Arabic text gets cut off in two main directions. A constrained box can hide the inline end of a line. A short box or a tight clipping boundary can hide glyphs above or below the baseline. The first may look like an abbreviated label; the second can make a correctly spelled word appear to have lost its marks. They need different fixes. Adding width to a box whose top edge cuts through a diacritic is unlikely to become a proud moment in debugging.
This guide uses a dictionary entry because fully vowelled words make vertical clipping visible. The same diagnosis applies to headings, buttons, badges and form controls. The focus here is text that CSS actually conceals.
Find the edge that is cutting the text#
Start with the visible edge, then inspect the element that owns it. A clipped word is often the child of the clipping box, not the box with the overflow declaration.
| What disappears | Inspect first | Why it matters |
|---|---|---|
| End of a single line | white-space, inline size, overflow, text-overflow | The line may be prevented from wrapping and hidden at its inline end. |
| Entire next line | Fixed height or block-size, line clamp, ancestor overflow | The text wrapped, but the container did not grow. |
| Top or bottom of glyphs | Line height, padding, font, clipping ancestor | The line may fit as a box while the visible ink touches a clip edge. |
| One part of a decorative label | clip-path, mask, transform or overlay | The CSS may conceal paint without changing the text's layout size. |
Open DevTools and select the affected text. Trace upward until you find a box whose edge lines up with the cut. Check computed overflow-x and overflow-y on every ancestor, not only the text node's own element. Then inspect white-space, height, min-height, line-height, padding, and any line-clamp rule. The declared stylesheet is a useful map, but the computed style tells you which rule won at this width.
Make one temporary change at a time. Disable the suspected overflow declaration. If the missing text appears outside the box, you found the clipping boundary. Disable a fixed height next. If the box grows and the text returns to its proper place, you found the constraint that made clipping necessary. This is a diagnostic sequence, not a suggestion to ship overflow: visible everywhere.
Two quick measurements can help locate box overflow:
const word = document.querySelector(".entry__word");
console.log({
horizontal: word.scrollWidth > word.clientWidth,
vertical: word.scrollHeight > word.clientHeight,
});Run this on a page containing .entry__word. A positive result says the content's scrollable area exceeds that element's client box. It does not identify which ancestor clips the paint, or whether the clipping was intended. A negative result does not prove every vowel mark is visible: box measurements and painted glyph edges are different things. Keep your eyes in the loop. They have been training for this task for years.
Reproduce the failure with real Arabic ink#
A dictionary interface might render a vowelled headword, a part-of-speech label and a definition:
<article class="entry" lang="ar" dir="rtl">
<div class="entry__heading">
<h2 class="entry__word">مَكْتَبَةٌ</h2>
<span class="entry__type">اسم</span>
</div>
<p class="entry__definition">مَكَانٌ تُحْفَظُ فِيهِ الْكُتُبُ</p>
</article>The exact rendering depends on the Arabic font. That is useful: if the product shows vowel marks, the test must use the font and marked words it will actually ship. A bare Arabic placeholder can fit a box that clips the real entry.
The heading puts the word and its label on one row in both languages:
.entry__heading {
display: flex;
align-items: baseline;
gap: 0.5rem;
}Here is a fragile styling choice for the headword:
Problem
.entry__word {
font-size: 2rem;
line-height: 1;
block-size: 2rem;
margin: 0;
overflow: hidden;
}The fixed block size leaves no room for the line to grow. Whether the font's marks visibly cross the edge requires a rendered check, but this combination gives them little margin. overflow: hidden then prevents anything outside the box from painting. The developer may have meant to align the headword with the label beside it. A fixed height on the word is a brittle way to do that.
Better
.entry__word {
font-size: 2rem;
line-height: 1;
min-block-size: 2rem;
margin: 0;
}
:lang(ar) .entry__word {
line-height: 1.5;
padding-block: 0.125em;
}The headword keeps at least its original height, but it can grow to fit its line and padding. The overflow clip is gone. The Arabic-specific spacing leaves the short English headword in its original layout. The :lang() selector follows the language inherited from the article. 1.5 is a starting value to test with this particular font and text, not a universal height for Arabic. Check the actual headword, including the upper and lower marks, beside the part-of-speech label in both directions. If the row's alignment changes, align the children through the parent layout rather than cutting the word down again.
overflow: hidden hides symptoms as well as decoration#
overflow: hidden has legitimate uses. It can crop an image to rounded corners or keep an animation inside a panel. Applied to a text-bearing element, it can conceal content that should have changed the layout. Applied to an ancestor, it may hide a child's glyphs even when the child itself has no overflow rule.
MDN's overflow reference distinguishes hidden from clip: both can conceal overflow, but hidden creates a scroll container while clip does not. Swapping one for the other does not give the text more room. It changes scrolling behavior, not the underlying size constraint. If the headword is cropped by a two-rem-high box, either value still leaves you with a cropped headword.
When the clip exists only to create rounded corners, consider where it belongs. An outer surface can clip an image layer while a separate inner text area has padding and enough block space. If the same element clips both decoration and text, the decorative requirement is allowed to veto readability. Separating those responsibilities may take an extra wrapper; that is an ordinary cost of having two different jobs.
Be careful with overflow: visible as a final fix. It can reveal the missing marks while allowing text to paint over the next control. The durable repair is to remove the inappropriate fixed size, increase spacing, or change the layout so the text has a place to go. Use visible overflow during diagnosis, then verify that no neighboring element is covered.
For a single-line box whose content is wider than the box, hidden overflow without an ellipsis is exactly the condition reports. It does not report every clipped diacritic or every hidden second line. Those need a visual test and a look at block sizing.
A clipped line ending is not a clipped vowel mark#
Suppose the dictionary entry has a compact search-result preview. Its headword and a short gloss are placed on one line. In Arabic, the line's end is on the left. If white-space: nowrap prevents wrapping and overflow: hidden is set, the leftward continuation can be cut off. The direction of the content determines which end is concealed; forcing text-align: right does not make the box wider.
The first question is whether the text should wrap. For a definition, usually yes:
.entry__definition {
white-space: normal;
overflow: visible;
}Then allow the parent to gain height. The MDN white-space reference explains that nowrap suppresses normal wrapping and can be inherited. If only one child of a toolbar should wrap, override the inherited rule on that child rather than changing the whole toolbar by accident.
If the line really is a preview, signal the missing content:
.entry__preview {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}The MDN text-overflow reference says a single ellipsis value marks the end of the line's direction. For RTL text, that is the left end. It also says text-overflow only concerns the inline direction. Adding text-overflow: ellipsis to a fixed-height paragraph does not mark a hidden line at the bottom. CSS will not infer your product's disclosure policy from a property name.
Check which element owns the rule. text-overflow applies to a block container; putting it on an ordinary inline span does not turn that span into a constrained preview. The element needs a finite available inline size and an overflow rule, and its text must be kept on the intended line. If the ellipsis never appears, inspect the selected element's display, available width and computed white-space before trying more punctuation. If it appears but the headword loses its distinguishing letters, the CSS is working and the product choice needs revision.
An ellipsis is acceptable only when the full entry is easy to reach. A dictionary headword may need to be visible in full because dropping its final letters can make it a different word. A short gloss may be a reasonable preview if the result opens to the full definition. Decide at the content level, then implement the intended behavior. specifically concerns clipping without an ellipsis; it cannot tell you whether an intentional ellipsis hides too much meaning.
Fixed height can cut a line that wrapped correctly#
The word may be complete, yet the definition's second line vanishes. That is a block-axis problem. The browser found a line break, but the container's fixed height or line clamp permits less vertical space than the text uses.
Inspect the parent and the text element separately. A child with height: auto can still be clipped by a parent with a fixed block size and overflow: hidden. Conversely, removing the parent's clip may expose text that overlaps the next entry because the parent remains too short. The visible boundary tells you where clipping occurs; the fixed height tells you why the content crossed it.
Use a minimum height when the design wants a consistent resting size, and let the text determine the actual height:
.entry__definition {
min-block-size: 3rem;
block-size: auto;
line-height: 1.6;
}Do not raise line-height alone inside a fixed-height box. More space between lines can move the final line farther beyond the same clip edge. Fix the box and the text rhythm together. reports Arabic body text with a line-height below 1.5; it is a prompt to inspect body copy, not a claim that every heading or font is safe at exactly 1.5.
If the design intentionally limits a description to two lines, use a supported clamping technique and provide the full definition in the detail view. MDN documents line-clamp and notes its support limits. Test the exact browser set you ship. A line count is also not a semantic limit: it may hide the word that distinguishes one definition from another. The product decision comes first; the CSS can then be honest about it.
Vowel marks need font-specific room#
Arabic diacritics can sit above and below letters, and more than one mark can attach to the same base character. The W3C Arabic and Persian layout requirements discusses those combinations and the role of font positioning. There is no single pixel amount that covers every font, size and marked word.
That is why visual testing must use actual vowelled content. Test a word with marks above, another with marks below, and a sample with stacked marks if your product contains one. View them at the sizes used in the interface, including the compact badge or button size. A font that looks generous in a paragraph may be cramped when the same text is placed inside a one-line control.
Inspect two layers of vertical space. First, the line box: line-height affects the space allocated to a line in horizontal writing modes, as the MDN line-height reference explains. Second, the element and any ancestor that clips overflow: padding and block size determine where their edges sit relative to the line. Increasing line height can help separate adjacent lines, but if the painted ink still touches a clipping edge, the box needs room there too.
Do not infer ink visibility from scrollHeight === clientHeight. Those values measure CSS boxes and scrollable overflow, not every outline of every rendered glyph. Nor does getBoundingClientRect() on the element provide the painted contour of each mark. Temporarily add a visible outline to the clipping ancestor, zoom in, and compare the glyphs against its top and bottom edges. If a mark appears after removing overflow: hidden, you have evidence of clipping that a neat pair of dimensions may have missed.
The edge case is intentional graphic cropping. A large decorative Arabic word might deliberately extend beyond a masked hero panel. That is a design choice if the word is not needed to understand or operate the page. A dictionary headword, button label or validation message does not get the same exemption merely because the clipping looks tidy.
Check the rendered font, not just font-family#
The declared CSS font may lack a glyph or fail to load. The browser can render Arabic with a fallback face whose letter widths and mark positions differ from the intended font. The result may appear only during loading or only on a device without the same local fonts. reports Arabic text falling back past the declared font family, including a failed webfont.
DevTools' computed font-family shows the requested stack, not necessarily the face that painted each Arabic character. Inspect the browser's rendered-font panel for the selected word. Then test twice: once after the webfont loads, and once with it unavailable. W3C's font fallback guidance explains why typography can change across faces.
If fallback is possible in the shipped product, the layout must tolerate it. Choose a fallback with reasonable Arabic coverage, give text enough space, and avoid fixed heights calculated from the primary font alone. The one pixel of extra room that made an English label fit has no contractual force over another typeface.
Do not squeeze Arabic with negative letter spacing to recover that pixel. Arabic letters normally connect; tracking can damage their joining. reports letter spacing applied to Arabic text. The MDN letter-spacing reference calls out this script-specific concern. Fix the available space or font selection instead.
Masks and overlays can imitate text clipping#
Sometimes no overflow: hidden appears in the ancestor chain, yet part of a word is still missing. Check paint effects. clip-path can restrict which part of an element is painted, and mask-image can make parts transparent without changing layout. MDN's CSS masking guide describes both. Temporarily disable these effects to see whether the lost text returns.
A positioned pseudo-element or gradient overlay can also sit above the letters. Inspect ::before and ::after, their background, stacking order and pointer behavior. A fade used on the English preview may cover a larger portion of the Arabic line after direction changes. This is not a line-height problem; increasing line-height may simply move the text under a different part of the overlay.
If fading is deliberate, anchor it to the actual inline end and keep the full text accessible. A physical left fade happens to be at the end of an RTL line, but would be at the start of an LTR one. Use a direction-aware implementation, then test both versions. The RTL CSS guide covers the larger question of logical edges. Here the immediate task is to confirm that the fade does not erase letters needed to identify the entry.
Do not confuse hidden paint with missing content. Copying text, inspecting the DOM or hearing a screen reader announce the complete word only confirms that the source still exists. It says nothing about whether the printed word on screen is complete.
Check controls at the sizes people actually use#
The dictionary headword may be fine while the compact “listen” button loses part of its Arabic label. Controls combine several constraints: a minimum tap area, padding, border, icon, label and sometimes a fixed height copied from the English design.
For a text-bearing control with class entry__listen, prefer a minimum block size with padding that permits the label to grow:
.entry__listen {
min-block-size: 2.75rem;
padding-block: 0.625rem;
padding-inline: 1rem;
line-height: 1.5;
white-space: normal;
}This does not say every button should have two lines. It says a translated label should not be silently clipped when the available width demands two. If the button must stay on one line, give it enough inline space or choose an approved shorter translation. An icon-only control can be appropriate when its meaning is clear and its accessible name remains present. Replacing every long Arabic label with an unexplained glyph is a remarkably compact way to create a different problem.
Test at browser zoom and with larger text settings, not just at the default desktop screenshot. Also check keyboard focus. A focus ring clipped by the same ancestor that clips the label can make the active control hard to find even after the text is fixed. Separate the decorative clipping layer from the interactive content if they have conflicting needs.
Input fields need their own pass. A short fixed-height input can cut typed Arabic text or its marks even when a nearby static label looks fine. Browser controls have their own rendering details, so test the actual input type, font and supported browsers. Do not apply a paragraph's line-height fix to every form control without checking the resulting cursor, placeholder and typed value.
Verify the fix without hiding another failure#
For every repaired component, test the same content before and after the CSS change. Keep the dictionary headword and definition constant, then vary the conditions that affect clipping:
- Default width and the narrowest width where the component appears.
- Primary Arabic font and the fallback face.
- Unmarked and vowelled words, including marks below the line.
- One line and multiple lines of definition text.
- Resting, focused, expanded and error states where the component has them.
- Normal zoom and enlarged text.
- RTL and LTR versions of the same layout.
Verify three things separately: the full text is painted where it must be, the containing box has grown or wrapped without covering neighbors, and any intentional truncation has a clear route to the full content. A fix that changes overflow: hidden to visible may pass the first check and fail the second. A new ellipsis may pass the second and fail the third.
Ritla can help identify the inline clipping pattern named by , and reports visible text-bearing elements that overlap. Neither replaces a close visual inspection of diacritics against a clipped line box. Keep a screenshot of the marked test word in your regression set, with the actual font loaded. That makes a future font or spacing change reviewable without asking someone to remember whether the kasra was visible last Tuesday.
Let the whole word remain visible#
The practical repair follows the edge that failed. For missing line endings, allow wrapping or make truncation explicit and reversible. For a hidden second line, let the box grow. For lost vowel marks, inspect the rendered font, line height and clipping boundary together. When a mask or overlay is responsible, move the decorative effect away from the text people need to read.
A free Ritla scan can surface clipped inline text and overlapping labels on the Arabic page. Use the result to locate the box, then test the marked words by eye at the widths and fonts you ship. If the text is escaping its container rather than being cut off, the horizontal overflow guide is the next stop. A dictionary can tolerate many things. A missing letter in the word it is defining should not be one of them.
Checks in this guide
- Clipped text: content wider than its box with overflow hidden and no ellipsis
- line-height below 1.5 on Arabic body text
- Arabic text falling back past the declared font family (measured, declared, or a webfont that failed to load)
- letter-spacing applied to Arabic text (breaks the connected script)
- Visible text-bearing elements overlapping