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.
<a id=s1 title="Section 1 Anchor" class=s></a>
<a id=s2 title="Section 2 Anchor" class=s></a>
<a id=s3 title="Section 3 Anchor" class=s></a>
<a id=s4 title="Section 4 Anchor" class=s></a>
<a id=s5 title="Section 5 Anchor" class=s></a>
<a id=s6 title="Section 6 Anchor" class=s></a>
<a id=s7 title="Section 7 Anchor" class=s></a>
<div id=progress></div>
<div id=background></div>
<nav class=prevnext role=presentation>
<ul>
<li class=p2><a href=#s1 accesskey=1 title="Trigger Section 1: This Page Refuses to Use Javascript"></a></li>
<li class="p3n1 starter"><a href=#s2 accesskey=2 title="Trigger Section 2: :target Pseudo Selector"></a></li>
<li class=p4n2><a href=#s3 accesskey=3 title="Trigger Section 3: ~ Swinton"></a></li>
<li class=p5n3><a href=#s4 accesskey=4 title="Trigger Section 4: Getting Cray / On Fleek"></a></li>
<li class=p6n4><a href=#s5 accesskey=5 title="Trigger Section 5: Accesskeys"></a></li>
<li class=p7n5><a href=#s6 accesskey=6 title="Trigger Section 6: Limitations"></a></li>
<li class=n6><a href=#s7 accesskey=7 title="Trigger Section 7: Acceptable Use Cases"></a></li>
</ul>
</nav>
<nav class=thumbs aria-label="table of contents">
<ul>
<li><a href=#s1 title="Thumbnail Trigger Section 1: This Page Refuses to Use Javascript"></a></li>
<li><a href=#s2 title="Thumbnail Trigger Section 2: :target Pseudo Selector"></a></li>
<li><a href=#s3 title="Thumbnail Trigger Section 3: ~ Swinton"></a></li>
<li><a href=#s4 title="Thumbnail Trigger Section 4: Getting Cray / On Fleek"></a></li>
<li><a href=#s5 title="Thumbnail Trigger Section 5: Accesskeys"></a></li>
<li><a href=#s6 title="Thumbnail Trigger Section 6: Limitations"></a></li>
<li><a href=#s7 title="Thumbnail Trigger Section 7: Acceptable Use Cases"></a></li>
</ul>
</nav>
<main role=main>
<section>
<article>
<h1>This pen refuses to use Javascript</h1>
<p>To navigate, you can use the prev/next buttons or the thumbnails to the right. If you prefer to get crazy, you can also use <code>accesskey</code> to jump to sections by using the following keyboard shortcuts:</p>
<pre>
Mac: alt + ctrl + [1-7]
PC Chrome/IE: alt + [1-7]
PC FF: alt + shift + [1-7]</pre>
<p class=right><small><a href="https://www.w3schools.com/tags/att_global_accesskey.asp" target="blank">More on accesskeys</a></small></p>
</article>
</section>
<section>
<article>
<h1>:target</h1>
<p>This interface relies on the CSS <code>:target</code> selector. An element is a “target” when its <code>id</code> is hash-referenced in the url.</p>
<pre><a href="http://example.com#section-1">Section 1</a></pre>
<pre>#section-1:target {
display: block;
}</pre>
<p>In the above example, whenever the link is clicked, the content with an <code>id</code> of <code>section-1</code> will be displayed.</p>
<p>CodePen removes the hash from the visible url, but right now you are looking at this pen with <code>#s2</code> as the target. If you were to manually add <code>#s2</code> to the end of this url and reload this pen, you will be taken to this screen instead of the first.</p>
</article>
</section>
<section>
<article>
<h1>~ Swinton</h1>
<p>In CSS, the tilde <code>~</code> is used as the “General sibling combinator”. In English, that means “any following sibling”.</p>
<pre>.a ~ .b {
display: none;
}</pre>
<p>This would hide any <code>.b</code> element that comes after an <code>.a</code> and is a sibling.</p>
<pre>
<div class="b">All good</div>
<div class="a">All good</div>
<div class="x">
<div class="b">Still good</div>
</div>
<div class="b">Hidden</div>
</pre>
<p>Only the last <code>.b</code> would be hidden. The first comes before the <code>.a</code>, and the second is not a direct sibling.</p>
</article>
</section>
<section>
<article>
<h1>Getting Cray / On Fleek</h1>
<p>By using <code>:target</code> and <code>~</code> we can do some pretty ridiculous things without touching Javascript. In this pen, we are using <code>:target</code> to trigger different state-related styles.</p>
<p>At the top of this pen, there are <code><a></code> elements. Their only purpose is being used as targets.</p>
<pre>
<a id="s1" class="s"></a>
<a id="s2" class="s"></a>
...
</pre>
<p>Using their <code>:target</code> state, we can then select and style anything else on the page.</p>
<p>Moving the main content area over <code>-300%</code> to reveal this fourth section.</p>
<pre>#s4:target ~ main {
left: -300%;
}</pre>
<p>Changing the background color and image:</p>
<pre>#s4:target ~ #background {
background-image: url(http://lorempixel.com/g/400/150/city/4/);
background-color: #265273;
}</pre>
<p>Changing the progress bar width:</p>
<pre>#s4:target ~ #progress {
width: 50%;
}</pre>
<p>Styling the fourth thumbnail as active:</p>
<pre>#s4:target ~ .thumbs li:nth-child(4) a {
opacity: 1;
width: 80px;
height: 60px;
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.1);
}</pre>
<p>Showing the appropriate previous link and making it say the right thing:</p>
<pre>#s4:target ~ .prevnext li[class*="p4"] {
display: block;
float: left;
}
#s4:target ~ .prevnext li[class*="p4"] a:after {
content: "Prev";
}</pre>
<p>Showing the appropriate next link and making it say the right thing:</p>
<pre>#s4:target ~ .prevnext li[class*="n4"] {
display: block;
float: right;
}
#s4:target ~ .prevnext li[class*="n4"] a:after {
content: "Next";
}</pre>
</article>
</section>
<section>
<article>
<h1>accesskeys</h1>
<p>Each of the next/prev navigation items link to each of these spans and have an <code>accesskey</code> attribute. This allows them to be fired using the browser’s <code>accesskey</code> plus whatever key is provided. In this case, we are using the corresponding section number.</p>
<pre>
<a href="#s1" accesskey="1"></a>
<a href="#s2" accesskey="2"></a>
...
</pre>
<p>Each browser and operating system use different keyboard shortcuts for <code>accesskey</code>, but the support is suprisingly universal.</p>
<pre>Mac: alt + ctrl
PC Chrome/IE: alt
PC FF: alt + shift</pre>
<p>To switch to the next section, you can hold down your <code>accesskey</code> combination above and then press <code>6</code>.
<p>There’s more to read about <code>accesskey</code> on <a href="https://www.w3schools.com/tags/att_global_accesskey.asp" target="blank">w3schools</a>.</p>
</article>
</section>
<section>
<article>
<h1>Limitations</h1>
<p>As with any “Who needs JS?” approach, there are more than a few things to consider when doing something like this.</p>
<h2>Accessibility</h2>
<p>Confining yourself to CSS makes any interactive experience more inaccessible. There are a handful of ways one could optimize this for screen readers more than I (hardly) have, but it would be a lot of effort for a unsatisfactory result.</p>
<p>Additionally, since the “prev/next” links are actually new links on each section change, the <code>:focus</code> that occurs when you have tabbed into them disappears because the link is actually disappearing. You need to re-tab in every time. Blech. No one likes excess tab unless we’re talking about <a href="https://en.wikipedia.org/wiki/Tab_(soft_drink)" title="Wikipedia: Tab Soda" target="blank">the soda</a>.</p>
<h2>History</h2>
<p>Each hashchange is going to be recorded in the browser history without some Javascript intervention. This can go either way as a pro or con. For something like this, it may be a pro.</p>
<h2>Scalability</h2>
<p>All ths content is being dumped into the DOM at once. At a certain size, this approach might not make a lot of sense. In theory, you could get around some of this with some smart selectors and <code>display: none;</code>, but depending on the complexity of your content, you may still have some load time issues. Dynamically loading content with Javascript is a often a very, very good thing.</p>
</article>
</section>
<section>
<article>
<h1>Acceptable Use Cases</h1>
<p>There are some cases where something this inaccessible is technically ok. This could make sense in an environment where it is only being used in a visual setting such as a live presentation or internal documentation tool.</p>
<p>Most importantly, it can be used as a way to show that CSS is very powerful, but can also be very limiting—depending on the need.</p>
<p>If you liked this, you may enjoy more of my bogus CSS in my <a href="https://codepen.io/collection/DzxNzN/" target="blank">No JS Collection</a>.</p>
</article>
</section>
</main>
@import url(https://fonts.googleapis.com/css?family=Merriweather:300,300italic|Inconsolata);
$border-color: rgba(#FFF,0.1);
$mobile-w: 600px;
$large-w: 1200px;
$thumb-w: 80px;
$thumb-h: 60px;
$thumb-pad: 10px;
$s-count: 7;
main {
position: absolute;
top: 0; left: 0; bottom: 0;
width: 100%;
transition: left 500ms;
}
//
// each section
section {
position: absolute;
top: 0; right: 0; bottom: 0;
width: 100%;
margin: 0;
opacity: 0;
box-sizing: border-box;
overflow: auto;
-webkit-overflow-scrolling: touch;
&:first-child {
opacity: 1;
}
transition: opacity 250ms ease-in-out;
article {
width: calc(90% - #{$thumb-w + $thumb-pad});
max-width: 800px;
padding: 4rem 0 4rem 5%;
color: #fff;
}
code, pre {
background: rgba(#000,0.5);
border: 1px solid $border-color;
border-radius: 4px;
box-sizing: border-box;
}
code {
padding: 0.25rem 0.5rem;
}
pre {
padding: 1rem;
margin: 1rem auto;
}
}
// main nav ids
.s {
position: absolute;
}
//
// navigation mixin styles
@mixin active-next() {
display: block;
float: right;
a:after { content: "Next"; }
}
@mixin active-prev() {
display: block;
float: left;
a:after { content: "Prev"; }
}
@mixin active-thumb {
opacity: 1;
width: $thumb-w;
height: $thumb-h;
box-shadow: 0px 0px 0px 1px $border-color;
}
@mixin inactive-thumb {
opacity: 0.5;
width: $thumb-w / 2;
height: $thumb-h / 2;
box-shadow: 0px 0px 0px 1px rgba(#FFF,0);
}
//
// navigation thumbs and buttons
nav {
position: fixed;
z-index: 1;
width: 100%;
user-select: none;
&.thumbs {
right: $thumb-pad;
top: 50%;
transform: translateY(-50%);
width: $thumb-w + $thumb-pad;
display: block;
ul {
margin: 0; padding: 0;
}
li {
display: block;
margin: 0 auto 0.5rem;
&:first-child a {
@include active-thumb();
}
a {
&:hover {
opacity: 1;
}
@include inactive-thumb();
margin: 0 auto;
display: block;
background-blend-mode: multiply;
background-position: center;
background-size: cover;
border-radius: 2px;
position: relative;
transition:
height 250ms ease-in-out,
width 250ms ease-in-out,
opacity 250ms ease-in-out,
box-shadow 250ms ease-in-out;
&:active {
transform: translateY(1px);
}
}
}
}
&.prevnext {
left: 0;
top: 1rem;
ul {
list-style: none;
margin: 0.5rem auto;
padding: 0;
width: 220px;
position: relative;
&:after {
content: "";
display: table;
clear: both;
}
li {
display: none;
width: 100px;
&.starter {
@include active-next();
}
}
a {
display: block;
width: 100%;
box-sizing: border-box;
padding: 0.5rem 1rem;
border-radius: 4px;
text-align: center;
box-shadow: 0px 0px 0px 0px $border-color;
border: 1px solid $border-color;
color: #FFFFFF;
background-color: rgba(#000,0.4);
transition: background 200ms ease-in-out 200ms,
box-shadow 200ms ease-in-out;
&:hover, &:active {
background-color: rgba(#000,0.5);
}
&:hover {
box-shadow: 0px -2px 0px 0px $border-color;
}
&:active {
box-shadow: 0px 0px 0px 0px $border-color;
transform: translateY(1px);
}
}
}
}
a {
text-decoration: none;
}
}
//
// slider experience on non mobile
@media (min-width: $mobile-w) {
main {
height: 100%;
}
}
//
// content position on large
@media (min-width: $large-w) {
main article {
padding-left: 0;
margin: 0 auto;
}
}
//
// prevnext buttons on non mobile
@media (min-width: $mobile-w) {
nav.prevnext {
top: auto;
bottom: 1rem;
}
}
//
// progress indicator at top of page
#progress {
position: fixed;
z-index: 9;
top: 0;
left: 0;
width: 0%;
border-bottom: 12px solid rgba(#FFF,0.2);
transition: width 1250ms linear;
}
//
// :target and other iterative styles
@for $i from 1 through $s-count {
//
// adjusting section opacity on all screens
#s#{$i}:target ~ main section {
opacity: 0;
&:nth-child(#{$i}) {
opacity: 1;
}
}
//
// adjusting section position on mobile screens
@media (max-width: $mobile-w - 1) {
#s#{$i}:target ~ main section {
top: 50%;
&:nth-child(#{$i}) {
top: 0;
}
}
}
//
// adjusting left position on big screens
@media (min-width: $mobile-w) {
// parent shift on target
#s#{$i}:target ~ main {
left: -100% * ($i - 1);
}
// individual
section:nth-child(#{$i}) {
left: 100% * ($i - 1);
}
}
.thumbs li:nth-child(#{$i}) a {
background-image: url(https://picsum.photos/400/150?a=#{$i}/);
background-color: hsl($i / $s-count * 360, 50, 30);
}
#s#{$i}:target ~ #background {
background-image: url(https://picsum.photos/400/150?a=#{$i}/);
background-color: hsl($i / $s-count * 360, 50, 30);
}
#s#{$i}:target ~ #progress {
width: ($i - 1) / ($s-count - 1) * 100%;
}
#s#{$i}:target ~ .thumbs li:first-child a {
@include inactive-thumb();
}
#s#{$i}:target ~ .thumbs li:nth-child(#{$i}) a {
@include active-thumb();
}
#s#{$i}:target ~ .prevnext li.starter {
display: none;
}
#s#{$i}:target ~ .prevnext li[class*="p#{$i}"] {
@include active-prev();
}
#s#{$i}:target ~ .prevnext li[class*="n#{$i}"] {
@include active-next();
}
}
//
// background image
#background {
background-image: url(https://picsum.photos/400/150?a=1/);
background-color: hsl(1 / 5 * 360, 50, 30);
background-blend-mode: multiply;
background-position: center;
background-size: cover;
$blur: 10px;
filter: blur($blur);
position: fixed;
z-index: -1;
transition:
background-image 500ms ease-in-out 500ms,
background-color 500ms ease-in-out 1000ms;
top: $blur * -2; right: $blur * -2; bottom: $blur * -2; left: $blur * -2;
}
//
// global non-essential styles
html, body {
height: 100%;
width: 100%;
overflow: hidden;
color: #FFF;
font-family: Merriweather, Georgia, serif;
font-weight: 300;
}
pre, code {
font-family: Inconsolata, monospace;
}
a {
color: #EEE;
}
h1, p {
font-weight: 300;
}
p, ul {
line-height: 1.6;
}
.right { text-align: right; }
Also see: Tab Triggers