Positioning Text Around Elements With CSS Offset

Home » Positioning Text Around Elements With CSS Offset

When it comes to positioning elements on a page, including text, there are many ways to go about it in CSS — the literal position property with corresponding inset-* properties, translate, margin, anchor() (limited browser support at the moment), and so forth. The offset property is another one that belongs in that list.

The offset property is typically used for animating an element along a predetermined path. For instance, the square in the following example traverses a circular path:

<div class="circle">
  <div class="square"></div>
</div>
@property --p 
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;

.square 
  offset: top 50% right 50% circle(50%) var(--p);
  transition: --p 1s linear;

  /* Equivalent to:
    offset-position: top 50% right 50%;
    offset-path: circle(50%);
    offset-distance: var(--p); */

  /* etc. */


.circle:hover .square --p: 100%; 
CodePen Embed Fallback

A registered CSS custom property (--p) is used to set and animate the offset distance of the square element. The animation is possible because an element can be positioned at any point in a given path using offset. and maybe you didn’t know this, but offset is a shorthand property comprised of the following constituent properties:

  • offset-position: The path’s starting point
  • offset-path: The shape along which the element can be moved
  • offset-distance: A distance along the path on which the element is moved
  • offset-rotate: The rotation angle of an element relative to its anchor point and offset path
  • offset-anchor: A position within the element that’s aligned to the path

The offset-path property is the one that’s important to what we’re trying to achieve. It accepts a shape value — including SVG shapes or CSS shape functions — as well as reference boxes of the containing element to create the path.

Reference boxes? Those are an element’s dimensions according to the CSS Box Model, including content-box, padding-box, border-box, as well as SVG contexts, such as the view-box, fill-box, and stroke-box. These simplify how we position elements along the edges of their containing elements. Here’s an example: all the small squares below are placed in the default top-left corner of their containing elements’ content-box. In contrast, the small circles are positioned along the top-right corner (25% into their containing elements’ square perimeter) of the content-box, border-box, and padding-box, respectively.

<div class="big">
  <div class="small circle"></div>
  <div class="small square"></div>
  <p>She sells sea shells by the seashore</p>
</div>

<div class="big">
  <div class="small circle"></div>
  <div class="small square"></div>
  <p>She sells sea shells by the seashore</p>
</div>

<div class="big">
  <div class="small circle"></div>
  <div class="small square"></div>
  <p>She sells sea shells by the seashore</p>
</div>
.small 
  /* etc. */
  position: absolute;

  &.square 
    offset: content-box;
    border-radius: 4px;
  

  &.circle  border-radius: 50%; 


.big 
  /* etc. */
  contain: layout; /* (or position: relative) */

  &:nth-of-type(1) 
    .circle  offset: content-box 25%; 
  

  &:nth-of-type(2) 
    border: 20px solid rgb(170 232 251);
    .circle  offset: border-box 25%; 
  

  &:nth-of-type(3) 
    padding: 20px;
    .circle  offset: padding-box 25%; 
  
CodePen Embed Fallback

Note: You can separate the element’s offset-positioned layout context if you don’t want to allocated space for it inside its containing parent element. That’s how I’ve approached it in the example above so that the paragraph text inside can sit flush against the edges. As a result, the offset positioned elements (small squares and circles) are given their own contexts using position: absolute, which removes them from the normal document flow.

This method, positioning relative to reference boxes, makes it easy to place elements like notification dots and ornamental ribbon tips along the periphery of some UI module. It further simplifies the placement of texts along a containing block’s edges, as offset can also rotate elements along the path, thanks to offset-rotate. A simple example shows the date of an article placed at a block’s right edge:

<article>
  <h1>The Irreplaceable Value of Human Decision-Making in the Age of AI</h1>
  <!-- paragraphs -->
  <div class="date">Published on 11<sup>th</sup> Dec</div>
  <cite>An excerpt from the HBR article</cite>
</article>
article 
  container-type: inline-size;
  /* etc. */


.date 
  offset: padding-box 100cqw 90deg / left 0 bottom -10px;
  
  /*
    Equivalent to:
    offset-path: padding-box;
    offset-distance: 100cqw; (100% of the container element's width)
    offset-rotate: 90deg;
    offset-anchor: left 0 bottom -10px;
  */
CodePen Embed Fallback

As we just saw, using the offset property with a reference box path and container units is even more efficient — you can easily set the offset distance based on the containing element’s width or height. I’ll include a reference for learning more about container queries and container query units in the “Further Reading” section at the end of this article.

There’s also the offset-anchor property that’s used in that last example. It provides the anchor for the element’s displacement and rotation — for instance, the 90 degree rotation in the example happens from the element’s bottom-left corner. The offset-anchor property can also be used to move the element either inward or outward from the reference box by adjusting inset-* values — for instance, the bottom -10px arguments pull the element’s bottom edge outwards from its containing element’s padding-box. This enhances the precision of placements, also demonstrated below.

<figure>
  <div class="big">4</div>
  <div class="small">number four</div>
</figure>
.small 
  width: max-content;
  offset: content-box 90% -54deg / center -3rem;

  /*
    Equivalent to:
    offset-path: content-box;
    offset-distance: 90%;
    offset-rotate: -54deg;
    offset-anchor: center -3rem;
  */

  font-size: 1.5rem;
  color: navy;
CodePen Embed Fallback

As shown at the beginning of the article, offset positioning is animateable, which allows for dynamic design effects, like this:

<article>
  <figure>
    <div class="small one">17<sup>th</sup> Jan. 2025</div>
    <span class="big">Seminar<br>on<br>Literature</span>
    <div class="small two">Tickets Available</div>
  </figure>
</article>
@property --d 
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;


.small 
  /* other style rules */
  offset: content-box var(--d) 0deg / left center;

  /*
    Equivalent to:
    offset-path: content-box;
    offset-distance: var(--d);
    offset-rotate: 0deg;
    offset-anchor: left center;
  */

  transition: --d .2s linear;

  &.one  --d: 2%; 
  &.two  --d: 70%; 


article:hover figure 
  .one  --d: 15%;  
  .two  --d: 80%;  
CodePen Embed Fallback

Wrapping up

Whether for graphic designs like text along borders, textual annotations, or even dynamic texts like error messaging, CSS offset is an easy-to-use option to achieve all of that. We can position the elements along the reference boxes of their containing parent elements, rotate them, and even add animation if needed.

Further reading


Positioning Text Around Elements With CSS Offset originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

​ 

Leave a Comment

Your email address will not be published. Required fields are marked *