CSSAMP is a CSS only framework for AMP HTML that styles frequently used HTML tags without the need for classes. It also provides a few utilities such as a responsive grid and CSS-only tooltips.
CSSAMP can be used as-is or as a base layer for a custom AMP document. This page doubles as both the demo and the reference implementation.
Designed for modern browsers and AMP-era documents.
No separate starter template is required. The patterns on this page are the project.
Sometimes you want to quickly set up a simple site or application. You don't want it to look like a Word™ doc but you also don't want or need a massive framework such as Bootstrap, Foundation, or Materialize.
In a similar vein to Pure and Skeleton, CSSAMP aims to provide a minimal CSS framework that requires minimal setup.
CSSAMP takes that minimal approach one step further by staying completely classless. Default styles are applied only to elements without classes, which keeps custom components and one-off modules easy to opt out of. If you want to keep the library styling on a tagged element, add the data-xx attribute.
CSSAMP effectively changes the default browser styles. Any commonly used tags such as input or button are styled only if they don't have any classes.
If you need to add a class to an element but still want the default CSSAMP styling, add the data-xx attribute to that same tag.
<!-- want to style a button? -->
<button>Button</button>
<!-- adding a class will remove the CSSAMP styling and use the default browser style -->
<button class="your-btn-class">Button</button>
<!-- adding the attribute data-xx to a tag with a class will apply the CSSAMP styling -->
<button data-xx class="your-btn-class">Button</button>
cssamp.cssmark elementdata- now to be AMP-compatiblea anchor tag added vertical-align:top to maintain consistent placementdata-xx default class has now been made an attributedata-tt it's now just data-ttdata-att attributeUse cssamp.css as the maintainable source stylesheet. For an AMP page, copy its contents into your document's single <style amp-custom> block, then include whichever AMP component scripts your page needs.
This is the better option if you want the CSSAMP styling but plan to write your own page structure or trim the framework down to a smaller set of patterns.
If you want a complete reference, start from index.html. It already contains the AMP boilerplate, inline stylesheet, embedded icons, and the demo markup used throughout the docs.
This is the better option if you want to copy the whole page, then remove the sections and examples you do not need.
The files are intentionally paired: cssamp.css is the clean stylesheet source, while index.html shows how that CSS is embedded inside a complete AMP document.
<!-- option 1: paste cssamp.css into your AMP page -->
<style amp-custom>
/* paste CSSAMP here */
</style>
<!-- option 2: start from index.html and trim it down -->
<!doctype html>
<html amp lang="en">
<head>
<script async src="https://cdn.ampproject.org/v0.js"></script>
<style amp-custom>...</style>
</head>
</html>
This site that you're viewing right now is built on section elements. The sections are horizontally centered, have a max-width equal to 90rem, and will shrink with smaller screens. Useful for containing content quickly.
Note: Because of CSS specificity, overwriting the default style with a class will require specifying that the class applies to a section element. Eg: Your CSS property should look like section.custom-section rather than just .custom-section.
<!-- use sections to quickly and easily contain content -->
<section>
Your code here.
</section>
Font sizes in CSSAMP are based on rems. You can change the scale by adjusting the html font size. The default is 10px, so 1rem maps neatly to 10px.
The font-family defaults are intentionally simple. data-serif, data-sans, and data-mono all draw from the CSS variables near the top of the stylesheet.
Heading styles mainly standardize spacing and scale, covering h1 through h6 without additional classes.
h1 Heading level 1h2 Heading level 2h3 Heading level 3h4 Heading level 4h5 Heading level 5h6 Heading level 6Tooltips are handy and CSSAMP provides you with classless, no javascript tooltips. Tooltips can be applied to most tags, as long as they accept the ::before and ::after pseudo elements. Just use data-tt="Your tooltip here" in the tag.
Hover over this for a tooltip on a b tag. Hover over this, or this or even this to see tooltips in action.
Note: These tooltips aren't clever so they will spill offscreen. You'll need some Javascript if you want dynamic positioning.
<!-- inline element -->
<b data-tt="Tooltip on a <b> tag">this</b>
<code data-tt="Tooltip on a <code> tag">this</code>
<a href="" data-tt="Tooltip on an anchor tag">this</a>
<sup data-tt="Tooltip on a <sup> tag">this</sup>
If you want to tell your user why a button is disabled then you can use the data-dtt attribute to show a tooltip when a button is disabled. This is handy for things such as invalid or incomplete forms.
You can use both data-tt and data-dtt on the same element and the button disabled state will determine the tooltip shown.
Enter some text to enable the disabled button.
<!-- disabled buttons -->
<!-- note that you can have tooltips for enabled and disabled states -->
<form method="GET" action="/" target="_top" on="valid:AMP.setState({disable: false});invalid:AMP.setState({disable: true})" custom-validation-reporting="as-you-go">
<label>Some Text</label>
<input type="text" placeholder="Type anything" required>
<span visible-when-invalid>Enter some text before submitting.</span>
<button disabled data-primary data-m-full data-xx [disabled]="disable" data-tt="Not disabled" data-dtt="Disabled button tooltip">Disabled button</button>
</form>
You can easily set a tooltip for an anchor link that shows the href on hover just by adding the data-att attribute.
<!-- anchor link tooltips with the data-att attribute -->
<a data-att href="https://github.com/morganmacarthur/CSSAMP">anchor link</a>
CSSAMP keeps the classless form approach, but covers more of the controls that used to fall through the cracks. Labels still work best directly after radio and checkbox inputs, while the other controls are sized to stay stable in normal document flow.
<fieldset>
<legend>Common controls</legend>
<label>Text Input</label>
<input type="text" placeholder="text">
<label>Text Area</label>
<textarea placeholder="more text"></textarea>
<label>Select</label>
<select>
<option disabled selected>Select an option</option>
<option>Option One</option>
<option>Option Two</option>
<option>Option Three</option>
</select>
<span>
<div data-col="1/2" data-fx>
<p><input type="checkbox" id="checkbox-1"> <label for="checkbox-1">Checkbox 1</label><br><input type="checkbox" id="checkbox-2"> <label for="checkbox-2">Checkbox 2</label></p>
</div>
<div data-col="1/2" data-fx>
<p><input type="radio" name="radio" id="radio-1"> <label for="radio-1">Radio 1</label><br><input type="radio" name="radio" id="radio-2"> <label for="radio-2">Radio 2</label></p>
</div>
</span>
</fieldset>
<label>Search</label>
<input type="search" placeholder="Search the document">
<label>Date</label>
<input type="date" value="2026-03-25">
<label>Current output</label>
<output>72%</output>
<label>Progress</label>
<progress value="72" max="100">72%</progress>
<label>Meter</label>
<meter min="0" max="100" low="30" high="80" optimum="90" value="72">72%</meter>
This example uses AMP form state attributes instead of broad success selectors, so submitting, success, and error messages appear without collapsing the rest of the form around them. The file field is included in the supported AMP pattern: a POST form with action-xhr.
<form method="post" action-xhr="https://amp.dev/documentation/examples/api/echo-json/post/" target="_top">
<label>Name</label>
<input type="text" name="name" placeholder="Morgan" required>
<label>Email</label>
<input type="email" name="email" placeholder="morgan@example.com" required>
<label>Attachment</label>
<input type="file" name="attachment" no-verify>
<div submitting>
<p>Sending your message...</p>
</div>
<div submit-success>
<template type="amp-mustache">
<p>Thanks {{name}}. The success state is now scoped so the form stays in place.</p>
</template>
</div>
<div submit-error>
<template type="amp-mustache">
<p>{{message}}</p>
</template>
</div>
<input type="submit" value="Send message" data-primary>
</form>
The code styles are intentionally light. If you want syntax highlighting, pair them with the tooling of your choice.
Here is some inline code.
if ( to_be || !to_be ) {
that = theQuestion;
}
<!-- inline code -->
<code>inline</code>
<!-- pre code -->
<pre><code>if ( to_be || !to_be ) {
that = theQuestion;
}</code></pre>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus luctus urna sed urna ultricies ac tempor dui sagittis. In condimentum facilisis porta. Sed nec diam eu diam mattis viverra. Nulla fringilla, orci ac euismod semper, magna diam porttitor mauris.
- Lorem Ipsum
<blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus luctus urna sed urna ultricies ac tempor dui sagittis. In condimentum facilisis porta. Sed nec diam eu diam mattis viverra. Nulla fringilla, orci ac euismod semper, magna diam porttitor mauris.</p>
<p data-txt="r"><i>- Lorem Ipsum</i></p>
</blockquote>
If the parent ul or ol is classless, or carries data-xx, the child li elements inherit the list styling automatically.
Tables use standard table, thead, tbody, tr, th, and td elements. If the table is classless, or marked with data-xx, the child elements pick up the library styling automatically.
When the user hovers over the head row, the relevant column will be highlighted. Any other row and the entire row will be highlighted.
| Title one | Title two | Title three | Title four |
|---|---|---|---|
| Row 1 col 1 | Row 1 col 2 | Row 1 col 3 | Row 1 col 4 |
| Row 2 col 1 | Row 2 col 2 | Row 2 col 3 | Row 2 col 4 |
| Row 3 col 1 | Row 3 col 2 | Row 3 col 3 | Row 3 col 4 |
| Row 4 col 1 | Row 4 col 2 | Row 4 col 3 | Row 4 col 4 |
The grid uses a plain span wrapper with child divs that declare widths through data-col.
There is no separate row element. Columns wrap naturally, and widths are expressed as fractions such as 1/3 and 2/3.
By default, each column expands to 100% width on mobile.
<!-- no need for rows, span will act as both row and container -->
<span>
<div data-col="1/12"><div><b>1/12</b></div></div>
<div data-col="11/12"><div><b>11/12</b></div></div>
<div data-col="1/6"><div><b>2/12</b> or <b>1/6</b></div></div>
<div data-col="5/6"><div><b>10/12</b> or <b>5/6</b></div></div>
<div data-col="1/4"><div><b>3/12</b> or <b>1/4</b></div></div>
<div data-col="3/4"><div><b>9/12</b> or <b>3/4</b></div></div>
<div data-col="1/3"><div><b>4/12</b> or <b>2/6</b> or <b>1/3</b></div></div>
<div data-col="2/3"><div><b>8/12</b> or <b>2/3</b></div></div>
<div data-col="5/12"><div><b>5/12</b></div></div>
<div data-col="7/12"><div><b>7/12</b></div></div>
<div data-col="1/2"><div><b>6/12</b> or <b>3/6</b> or <b>2/4</b> or <b>1/2</b></div></div>
<div data-col="1/2"><div><b>6/12</b> or <b>3/6</b> or <b>2/4</b> or <b>1/2</b></div></div>
<div data-col="1/1"><div><b>1/1</b></div></div>
</span>
The grid columns will automatically expand to 100% width when the viewport reaches the @mobile width. To prevent this, add the data-fx attribute to the column.
<!-- adding data-fx to the data-col will retain width on mobile -->
<span>
<div data-fx data-col="5/12"><div><b>5/12</b></div></div>
<div data-fx data-col="7/12"><div><b>7/12</b></div></div>
<div data-fx data-col="1/2"><div><b>1/2</b></div></div>
<div data-fx data-col="1/2"><div><b>1/2</b></div></div>
</span>
You can place a span inside of data-col to nest grids. You can do this as many times as you like.
<!-- you can nest a span inside a col -->
<span>
<div data-col="1/2"><div><b>1/2</b></div></div>
<div data-col="1/2">
<!-- nested grid -->
<span>
<div data-col="1/1"><div><b>1/1</b></div></div>
<div data-col="1/2"><div><b>1/2</b></div></div>
<div data-col="1/2"><div><b>1/2</b></div></div>
</span>
</div>
</span>
The examples here are all columns inside a span, separated with hr elements.
<!-- you can use a hr to separate cols -->
<span>
<div data-col="1/2"></div>
<div data-col="1/2"></div>
<hr>
<div data-col="1/2"></div>
<div data-col="1/2"></div>
</span>
Cards use the figure element and fit naturally inside the grid examples shown on this page.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.
<span>
<div data-col="1/3">
<figure>
<h5>Card one</h5>
<hr>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</figure>
</div>
<div data-col="1/3">
<figure>
<h5>Card two</h5>
<hr>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore.</p>
</figure>
</div>
<div data-col="1/3">
<figure>
<h5>Card three</h5>
<hr>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.</p>
</figure>
</div>
</span>
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae.
<!-- image at the top -->
<figure>
<amp-img data-xx src="https://uimgs.com/640x427/rainbow.jpg" width="640" height="427" layout="responsive">
</amp-img>
<h5>Top image</h5>
<p>Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae.</p>
</figure>
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae.
<!-- image in the middle -->
<figure>
<h5>Middle image</h5>
<amp-img data-xx src="https://uimgs.com/640x427/rainbow.jpg" width="640" height="427" layout="responsive">
</amp-img>
<p>Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae.</p>
</figure>
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae.
<!-- image at the bottom -->
<figure>
<h5>Bottom image</h5>
<p>Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae.</p>
<amp-img data-xx src="https://uimgs.com/640x427/rainbow.jpg" width="640" height="427" layout="responsive">
</amp-img>
</figure>
CSSAMP has a few utility attributes to make laying out a site a little faster. Sometimes you don't need to give an element a unique class to make it's text align right. Use these attributes to apply quick styles such as paddings or margins.
| Attribute | Values | Effect |
|---|---|---|
data-full |
null | Width 100% |
data-hide |
null | Display none |
data-fs |
xs s m l xl |
Sets font sizes from 1.1rem to 2.4rem |
data-mt |
0 2 4 8 |
Sets margin-top from 0 to 8rem |
data-mb |
0 2 4 8 |
Sets margin-bottom from 0 to 8rem |
data-pt |
0 2 4 8 |
Sets padding-top from 0 to 8rem |
data-pb |
0 2 4 8 |
Sets padding-bottom from 0 to 8rem |
data-pa |
0 2 |
Either removes all padding or sets padding for all sides to 2rem |
data-txt |
l c r j |
Sets text alignment to left, center, right or justify |
<!-- margin top 2rem + margin bottom 4rem -->
<div data-mt="2" data-mb="4"></div>
<!-- padding all 2rem -->
<p data-pa="2"></p>
<!-- text align right + font size small -->
<p data-txt="r" fs="s"></p>