HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
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.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
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.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
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.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<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>
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;
}
}
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;
});
Also see: Tab Triggers