Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <main>
  <nav>
    <div class="pretty">
      <input type="checkbox" switch id="pretty" name="pretty"> 
      <label for="pretty">text-wrap: pretty</label>
    </div>
    <div class="hyphens">
      <input type="checkbox" switch id="hyphens" name="hyphens"> 
      <label for="hyphens">hyphenate</label> 
    </div>
    <div class="justify">
      <input type="checkbox" switch id="justify" name="justify"> 
      <label for="justify">justify</label> 
    </div>
    <div class="guides">
      <input type="checkbox" switch id="guides" name="guides"> 
      <label for="guides">show guides</label> 
    </div> 
    <div class="ghosts">
      <input type="checkbox" switch id="ghosts" name="ghosts"> 
      <label for="ghosts">show ghosts</label> 
    </div> 
    <div class="balance">
      <input type="checkbox" switch id="balance" name="balance"> 
      <label for="balance">text-wrap: balance</label>
    </div>
<!--     <label for="widthSlider">Width: <span id="widthValue">500</span>px</label>
    <input type="range" id="widthSlider" min="100" max="900" value="500" step="10"> -->
  </nav>

  <article id="text">

<!------------ English lorum ispum ------------>
    
    <section class="language-block" lang="en">  
      <div class="ideal-line"></div>
      <div class="new-limit-line"></div>
      <div class="paragraph-pair">
        <p>Often, when people create layouts of text for the sake of design, they fill it with a lot of text. That text is not “real”. It’s far text meant simply to fill up the space, and provide for the opportunity to see if the layout of the content works under all conditions. People may be discovering that this text has short a lot of words all in a row. Or perhaps larger words covering a greater distance demonstrate hyphenation alongside complicated powerfully descriptive phraseology.</p>
        <p aria-hidden="true">Often, when people create layouts of text for the sake of design, they fill it with a lot of text. That text is not “real”. It’s far text meant simply to fill up the space, and provide for the opportunity to see if the layout of the content works under all conditions. People may be discovering that this text has short a lot of words all in a row. Or perhaps larger words covering a greater distance demonstrate hyphenation alongside complicated powerfully descriptive phraseology.</p>
      </div>
      <div class="paragraph-pair">
        <p>It’s also important to test paragraphs of different lengths. Some paragraphs are actually really short. Often that short paragraph shows off something punchy. </p>
        <p aria-hidden="true">It’s also important to test paragraphs of different lengths. Some paragraphs are actually really short. Often that short paragraph shows off something punchy. </p>
      </div>
      <div class="paragraph-pair">
        <p>By being terse you can make a point that your sentences are important. But other times we just have a lot of things to say and it takes a lot of words to say it all. So you go on and on about the choices before you. Hopefully, web designers are fully using all of the many, powerful features that CSS now has. It used to be very hard to style text on the web, and now it’s much easier. Floats can now be used for their original purpose. And CSS Grid can be used to create layouts on the page. Meanwhile, the many new typography features that shipped in the last couple years take text on the web to the next level.</p>
        <p aria-hidden="true">By being terse you can make a point that your sentences are important. But other times we just have a lot of things to say and it takes a lot of words to say it all. So you go on and on about the choices before you. Hopefully, web designers are fully using all of the many, powerful features that CSS now has. It used to be very hard to style text on the web, and now it’s much easier. Floats can now be used for their original purpose. And CSS Grid can be used to create layouts on the page. Meanwhile, the many new typography features that shipped in the last couple years take text on the web to the next level.</p>
      </div>
    </section>
    
    <hr>    
<!------------ Arabic lorum ispum ------------>
    
  <section lang="ar" class="ar language-block">
    <div class="ideal-line"></div>
    <div class="new-limit-line"></div>
    <div class="paragraph-pair">
      <p>عندما يُصمم النص لأغراض التصميم، غالبًا ما يكون مليئًا بكمية كبيرة من النصوص. هذا النص ليس "حقيقيًا"، بل هو موجود فقط لملء الفراغات واختبار مدى فعالية تخطيط المحتوى في جميع الظروف. قد تلاحظ أن هذا النص يحتوي على العديد من الكلمات المتتالية. أو ربما تشير الكلمات الأطول على مسافة أطول إلى استخدام الواصلة، بالإضافة إلى عبارات وصفية معقدة.</p>
      <p aria-hidden="true">عندما يُصمم النص لأغراض التصميم، غالبًا ما يكون مليئًا بكمية كبيرة من النصوص. هذا النص ليس "حقيقيًا"، بل هو موجود فقط لملء الفراغات واختبار مدى فعالية تخطيط المحتوى في جميع الظروف. قد تلاحظ أن هذا النص يحتوي على العديد من الكلمات المتتالية. أو ربما تشير الكلمات الأطول على مسافة أطول إلى استخدام الواصلة، بالإضافة إلى عبارات وصفية معقدة.</p>
    </div>
    <div class="paragraph-pair">
      <p>
من المهم أيضًا اختبار فقرات متفاوتة الطول. بعض الفقرات قصيرة جدًا في الواقع. غالبًا ما تنقل الفقرة القصيرة شيئًا موجزًا.</p>
      <p aria-hidden="true">
من المهم أيضًا اختبار فقرات متفاوتة الطول. بعض الفقرات قصيرة جدًا في الواقع. غالبًا ما تنقل الفقرة القصيرة شيئًا موجزًا.</p> 
    </div>
    <div class="paragraph-pair">
      <p>
يمكن للإيجاز أن يُبرز معنى الجمل. مع ذلك، في بعض الأحيان، يكون لديك الكثير لتقوله وتحتاج إلى الكثير من الكلمات. لذا، تتحدث بلا نهاية عن الإمكانيات المتاحة لك. نأمل أن يستفيد مصممو الويب استفادة كاملة من ميزات CSS القوية العديدة. كان تنسيق النصوص على الويب صعبًا للغاية في الماضي، ولكنه اليوم أسهل بكثير. يمكن الآن استخدام العناصر العائمة لغرضها الأصلي، ويمكن استخدام CSS Grid لإنشاء تخطيطات على الصفحة.</p>
   <p aria-hidden="true">
يمكن للإيجاز أن يُبرز معنى الجمل. مع ذلك، في بعض الأحيان، يكون لديك الكثير لتقوله وتحتاج إلى الكثير من الكلمات. لذا، تتحدث بلا نهاية عن الإمكانيات المتاحة لك. نأمل أن يستفيد مصممو الويب استفادة كاملة من ميزات CSS القوية العديدة. كان تنسيق النصوص على الويب صعبًا للغاية في الماضي، ولكنه اليوم أسهل بكثير. يمكن الآن استخدام العناصر العائمة لغرضها الأصلي، ويمكن استخدام CSS Grid لإنشاء تخطيطات على الصفحة.</p> 
    </div>
   </section>  
    
    <hr>
<!------------ German lorum ispum ------------>
    
    <section lang="de" class="language-block">
      <div class="ideal-line"></div>
      <div class="new-limit-line"></div>
      <div class="paragraph-pair">
        <p>Wenn Text zu Designzwecken erstellt wird, ist er oft sehr umfangreich. Dieser Text ist nicht „echt“. Er dient lediglich dazu, Platz zu füllen und zu testen, ob das Layout des Inhalts unter allen Bedingungen funktioniert. Möglicherweise fällt Ihnen auf, dass dieser Text viele Wörter hintereinander enthält. Längere Wörter über einen längeren Abstand deuten auf Silbentrennung hin, ebenso wie komplizierte, beschreibende Formulierungen.</p>
        <p aria-hidden="true">Wenn Text zu Designzwecken erstellt wird, ist er oft sehr umfangreich. Dieser Text ist nicht „echt“. Er dient lediglich dazu, Platz zu füllen und zu testen, ob das Layout des Inhalts unter allen Bedingungen funktioniert. Möglicherweise fällt Ihnen auf, dass dieser Text viele Wörter hintereinander enthält. Längere Wörter über einen längeren Abstand deuten auf Silbentrennung hin, ebenso wie komplizierte, beschreibende Formulierungen.</p>
      </div>
      <div class="paragraph-pair">
        <p>Es ist auch wichtig, Absätze unterschiedlicher Länge zu testen. Manche Absätze sind tatsächlich sehr kurz. Oft vermittelt ein kurzer Absatz etwas Prägnantes.</p>
        <p aria-hidden="true">Es ist auch wichtig, Absätze unterschiedlicher Länge zu testen. Manche Absätze sind tatsächlich sehr kurz. Oft vermittelt ein kurzer Absatz etwas Prägnantes.</p>
      </div>    
      <div class="paragraph-pair">
        <p>Prägnanz kann die Bedeutung von Sätzen unterstreichen. Manchmal hat man aber einfach viel zu sagen und braucht dafür viele Worte. Man spricht also endlos über die Möglichkeiten, die einem zur Verfügung stehen. Hoffentlich nutzen Webdesigner die vielen leistungsstarken Funktionen von CSS voll aus. Früher war es sehr schwierig, Text im Web zu formatieren, heute ist es viel einfacher. Floats können nun für ihren ursprünglichen Zweck verwendet werden. Und CSS Grid kann zum Erstellen von Layouts auf der Seite verwendet werden.</p>
        <p aria-hidden="true">Prägnanz kann die Bedeutung von Sätzen unterstreichen. Manchmal hat man aber einfach viel zu sagen und braucht dafür viele Worte. Man spricht also endlos über die Möglichkeiten, die einem zur Verfügung stehen. Hoffentlich nutzen Webdesigner die vielen leistungsstarken Funktionen von CSS voll aus. Früher war es sehr schwierig, Text im Web zu formatieren, heute ist es viel einfacher. Floats können nun für ihren ursprünglichen Zweck verwendet werden. Und CSS Grid kann zum Erstellen von Layouts auf der Seite verwendet werden.</p>
      </div>
    </section>

<!------------ Foobar lorum ispum ------------>
    
    <section lang="">    
      <div class="paragraph-pair">
        <p></p>
        <p aria-hidden="true"></p>
      </div>
      <div class="paragraph-pair">
        <p></p>
        <p aria-hidden="true"></p>
      </div>    
      <div class="paragraph-pair">
        <p></p>
        <p aria-hidden="true"></p>
      </div>
    </section>

    <hr>
<!------------ Chinese (Simplified) lorum ispum ------------>
    
    <section lang="zh" class="language-block">    
      <div class="ideal-line"></div>
      <div class="new-limit-line"></div>      
      <div class="paragraph-pair">
        <p>当文本用于设计目的时,它通常会填充大量文本。这些文本不是“真实的”。它们只是为了填充空间并测试内容布局是否在所有条件下都有效。您可能会注意到此文本包含连续的多个单词。或者,较长的单词在较长的距离上表示连字符,以及复杂的描述性短语。</p>
        <p aria-hidden="true">当文本用于设计目的时,它通常会填充大量文本。这些文本不是“真实的”。它们只是为了填充空间并测试内容布局是否在所有条件下都有效。您可能会注意到此文本包含连续的多个单词。或者,较长的单词在较长的距离上表示连字符,以及复杂的描述性短语。</p>
      </div>
      <div class="paragraph-pair">
        <p>测试不同长度的段落也很重要。有些段落实际上非常短。通常,短段落传达一些简洁的内容。</p>
        <p aria-hidden="true">测试不同长度的段落也很重要。有些段落实际上非常短。通常,短段落传达一些简洁的内容。</p>
      </div>    
      <div class="paragraph-pair">
        <p>简洁可以强调句子的含义。然而,有时您只是有很多话要说,需要很多话来表达。因此,您会无休止地谈论您可以使用的可能性。希望网页设计师能够充分利用 CSS 的许多强大功能。过去在网络上格式化文本非常困难,但今天却容易得多。浮动现在可以用于其原始目的。并且 CSS 网格可用于在页面上创建布局。</p>
        <p aria-hidden="true">简洁可以强调句子的含义。然而,有时您只是有很多话要说,需要很多话来表达。因此,您会无休止地谈论您可以使用的可能性。希望网页设计师能够充分利用 CSS 的许多强大功能。过去在网络上格式化文本非常困难,但今天却容易得多。浮动现在可以用于其原始目的。并且 CSS 网格可用于在页面上创建布局。</p>
      </div>
    </section>
    
    <hr>
<!------------ Japanese lorum ispum ------------>
 
    <section lang="ja" class="language-block">  
      <div class="ideal-line"></div>
      <div class="new-limit-line"></div>
      <div class="paragraph-pair">
        <p>テキストがデザイン目的でデザインされる場合、多くの場合、大量のテキストが詰め込まれます。このテキストは「本物」ではありません。単にスペースを埋め、あらゆる状況でコンテンツ レイアウトが機能するかどうかをテストするためにあります。このテキストには、多くの単語が連続して含まれていることに気付くかもしれません。または、長い単語が長い間隔で並んでいる場合は、ハイフンが使用されていることや、複雑な説明的なフレーズが含まれている可能性があります。</p>
        <p aria-hidden="true">テキストがデザイン目的でデザインされる場合、多くの場合、大量のテキストが詰め込まれます。このテキストは「本物」ではありません。単にスペースを埋め、あらゆる状況でコンテンツ レイアウトが機能するかどうかをテストするためにあります。このテキストには、多くの単語が連続して含まれていることに気付くかもしれません。または、長い単語が長い間隔で並んでいる場合は、ハイフンが使用されていることや、複雑な説明的なフレーズが含まれている可能性があります。</p>
      </div>
      <div class="paragraph-pair">
        <p>さまざまな長さの段落をテストすることも重要です。段落の中には、実際には非常に短いものもあります。多くの場合、短い段落は簡潔な内容を伝えます。</p>
        <p aria-hidden="true">さまざまな長さの段落をテストすることも重要です。段落の中には、実際には非常に短いものもあります。多くの場合、短い段落は簡潔な内容を伝えます。</p>
      </div>
      <div class="paragraph-pair">
        <p>簡潔さは、文の意味を強調できます。ただし、伝えたいことがたくさんあり、それを表現するために多くの単語が必要になることもあります。そのため、利用できる可能性について延々と話します。Web デザイナーが CSS の多くの強力な機能を最大限に活用していることを願います。以前は Web 上でテキストをフォーマットするのは非常に困難でしたが、今日でははるかに簡単になりました。フロートを本来の目的に使用できるようになりました。また、CSS グリッドを使用して、ページ上にレイアウトを作成できます。</p>
        <p aria-hidden="true">簡潔さは、文の意味を強調できます。ただし、伝えたいことがたくさんあり、それを表現するために多くの単語が必要になることもあります。そのため、利用できる可能性について延々と話します。Web デザイナーが CSS の多くの強力な機能を最大限に活用していることを願います。以前は Web 上でテキストをフォーマットするのは非常に困難でしたが、今日でははるかに簡単になりました。フロートを本来の目的に使用できるようになりました。また、CSS グリッドを使用して、ページ上にレイアウトを作成できます。</p>
      </div>
    </section>
    
    <hr>


  </article>
</main>







<footer class="error-message"><small>This is a demo of <code>text-wrap: pretty</code>. Your browser does not <a href="https://caniuse.com/mdn-css_properties_text-wrap_pretty" target="_blank">have support</a>. Try it in a browser that does, which curently (in March 2025) includes <a href="https://developer.apple.com/safari/resources/" target="_blank">Safari Technology Preview 216</a>.</small></footer>
              
            
!

CSS

              
                body:has(input[id="pretty"]:checked) .paragraph-pair p:nth-child(1) {
  text-wrap: pretty;
}
body:has(input[id="balance"]:checked) .paragraph-pair p:nth-child(1) {
  text-wrap: balance;
}
body:has(input[id="hyphens"]:checked) p {
  hyphens: auto;
}
body:has(input[id="justify"]:checked) p {
  text-align: justify;
}

/* --------------------------------------
   Reset    
-------------------------------------- */

* { box-sizing: border-box; }
:root { color-scheme: light dark; }
html { background: light-dark(white, black); }
body { margin: 0; }
.ar { direction: rtl;}
hr {
  border: none;
  border-top: 1px solid #ccc;
  margin: 3rem 33%;
}


/* --------------------------------------
   Overall layout & styling
-------------------------------------- */
main {
  display: grid;
/*   grid-template-columns: cal(var(--controls-width) + 4rem ) 1fr calc(var(--controls-width)/2);   */
  grid-template-columns: 18rem 1fr 8rem;
}
article {
  grid-column: 2;
  margin-block: 4rem;
  margin-inline: 5ch;
}
section {
  position: relative;
}
p {
  font-size: 1.2rem;
  font-family: Georgia;
  color: light-dark(#444, white);
  line-height: 1.4;
  margin-block: 1lh;
}
a {
  color: light-dark(#444, white);
  text-decoration: none;
}


/* --------------------------------------
   Ghosts
-------------------------------------- */

body:has(input[id="ghosts"]:not(:checked)) .paragraph-pair p:nth-child(2) {
  display: none;
}
.paragraph-pair {
  position: relative;
}
.paragraph-pair p:nth-child(2) {
  position: absolute;
  z-index: -1;
  inset-block-start: 0;
  inset-inline-start: 0;
  margin: 0;
  color: light-dark(#9ff2f2, #0f6666);
}

/* --------------------------------------
   Guides
-------------------------------------- */
:root {
  --ideal-target-offset: 45px; 
  /*textWrapPrettyMaxStretch * textWrapPrettyStretchability*/
  --inner-limit-offset: 90px;
  /* textWrapPrettyMaxStretch * textWrapPrettyStretchability + textWrapPrettyMaxShrink * textWrapPrettyShrinkability*/
  --box-edge: light-dark(#eee, #333);
  --ideal-target: light-dark(#06b406, #00a700);
  --inner-limit: light-dark(magenta, #940094);
  --outer-limit: light-dark(red, #b60000);
}
.language-block {
  border: 1.5px solid transparent;
}
body:has(input[id="guides"]:checked) {
  .language-block {
    border-color: var(--box-edge);
    border-inline-end-color: var(--ideal-target);
  }
  &:has(input[id="pretty"]:checked) {
    .language-block {
      border-inline-end-color: var(--outer-limit);
    }
    .ideal-line, .new-limit-line {
      position: absolute;
      inset-block-start: 0;
      inset-block-end: 0;
      width: 1.5px;
    }
    .ideal-line {
      background-color: var(--ideal-target);
      inset-inline-end: var(--ideal-target-offset);
    }
    .new-limit-line {
      background-color: var(--inner-limit);
      inset-inline-end: var(--inner-limit-offset);
      width: 1.3px;
    }
  }
}


/* --------------------------------------
   Controls
-------------------------------------- */
:root {
  --controls-width: 16rem; 
}
nav {
  align-self: start;
  float: left;
  position: sticky;
  top: 0;
  width: var(--controls-width);
  background: light-dark(rgba(249, 244, 244, 0.96), rgb(37, 66, 13, 0.95));
  box-shadow: 0 -1px 13px rgba(0, 0, 0, 0.2);
  padding: 1rem 1rem 0.5rem;
  z-index: 3;
  div {
    margin-block-end: 0.4rem;
  }
}
input {
  accent-color: light-dark(purple, yellow);
}
label, input {
  vertical-align: middle;
}
label {
  font-family: monospace;
  font-size: 1rem;
  padding-left: 0.33rem;
}
body:has(input[id="pretty"]:checked) .pretty label,
body:has(input[id="hyphens"]:checked) .hyphens label, 
body:has(input[id="justify"]:checked) .justify label, 
body:has(input[id="guides"]:checked) .guides label,
body:has(input[id="ghosts"]:checked) .ghosts label,
body:has(input[id="balance"]:checked) .balance label {
  color: light-dark(purple, yellow);  
}


/* --------------------------------------
   Error message for lack of support
-------------------------------------- */

.error-message { display: none; }
@supports not (text-wrap: pretty) {
  .error-message {
    color: white;
    padding: 2rem;
    margin-right: 3rem;
    background: darkred;
    display: block;
    text-align: center;
    font-size: 1.3rem;
    font-family: ui-system, sans-serif;
    a {
      color: #f1f170;
    }
    position: fixed;
    top: 50px;
    left: 290px;
  }
}
              
            
!

JS

              
                const rootStyles = document.documentElement.style;
const widthSlider = document.getElementById('widthSlider');
const widthValueDisplay = document.getElementById('widthValue');
const textContent = document.getElementById('text');
const sliderContainer = document.getElementById('slider-container');

document.body.addEventListener('click', (event) => {
  if (event.target.tagName !== 'BUTTON') return;

  const group = event.target.dataset.group;
  if (!group) return;

  // Remove 'selected' class from buttons in the same group
  document.querySelectorAll(`button[data-group="${group}"]`).forEach(btn => btn.classList.remove('selected'));

  // Apply selected class
  event.target.classList.add('selected');

  // Update styles based on button selection
  if (group === 'justify') {
    textContent.style.textAlign = event.target.id === 'justifyOnBtn' ? 'justify' : 'left';
  } else if (group === 'hyphen') {
    textContent.style.hyphens = event.target.id === 'hyphenOnBtn' ? 'auto' : 'none';
  }
});

widthSlider.addEventListener('input', () => {
  const width = widthSlider.value;
  document.body.style.width = `${width}px`;
  widthValueDisplay.textContent = width;
});
              
            
!
999px

Console