pasine
pasine

Reputation: 11543

Letter-spacing wrong text center alignment

I have noticed a odd behavior in using letter-spacing and text-align: center together. Increasing the space, bring the text to be closer to the left margin of the element.

div {
  width: 400px;
  height: 200px;
  background-color: #3b0d3b;
  text-align: center;
  margin: auto;
}

p {
  color: #fff;
  margin-top: 40px;
  text-align: center;
  padding-top: 10px;
  font-size: 1.2em;
}

.spacing {
  letter-spacing:.4em; /* This property is the problem */
}

.spacing-large {
  letter-spacing:.9em; /* This property is the problem */
}
<div>
  <p>- Foo Bar Zan -</p>
  <p class="spacing">- Foo Bar Zan -</p>
  <p class="spacing-large">- Foo Bar Zan -</p>
</div>

I spot the same behavior on last Firefox and Chrome. Is there a way to fix this issue?

Upvotes: 45

Views: 37556

Answers (8)

Panetta
Panetta

Reputation: 31

It probably depends on your use-case but using flexbox and a CSS ::before selector might be a viable solution if you still want to allow padding on the parent container without affecting the content.

.tracking-center {
  letter-spacing: 0.25em;
  display: flex;
  justify-content:center;
  text-align:center;
}

.tracking-center.inline-flex {
  display: inline-flex;
}

.tracking-center::before {
  width: 0.25em;
  content: '';
  flex: none;
}
<h3>Example</h3>
<div style="width:80px">
  <p class="tracking-center">
   Hello
  </p>
  <p class="tracking-center">
   The quick brown fox jumps over the lazy dog
  </p>
</div>

<h3>Example: Inline container with its own padding</h3>
<div style="width:200px">
  <p class="tracking-center inline-flex" style="padding:0 2em;">
   Hello
  </p>
  <p class="tracking-center inline-flex" style="padding:0 2em;">
   The quick brown fox jumps over the lazy dog
  </p>
</div>

<h3>Example: Container too narrow</h3>
<div style="width:20px; margin-left: 50px;">
  <p class="tracking-center">
   Hello
  </p>
  <p class="tracking-center">
   The quick brown fox jumps over the lazy dog
  </p>
</div>

<style>
<!-- example styles -->
div {
  border:2px cyan dotted;
}

p {
 border:2px pink dotted;
 display: inline-block;
}
.tracking-center::before {
  background:turquoise;
}
</style>

If you want to add a wrapper-container inside your element every time, you can simply specify a margin/padding on the inner-container like others have suggested

 .tracking-center > * {
   letter-spacing: 0.25em;
   margin-left: 0.25em; //or negative margin-right;
   text-align: center;
   display: block;
 }
<h3>Example</h3>
<div style="width:80px">
  <p class="tracking-center">
    <span>
     Hello
   </span>
  </p>
  <p class="tracking-center">
   <span>
     The quick brown fox jumps over the lazy dog
   </span>
  </p>
</div>

<h3>Example: Inline container with its own padding</h3>
<div style="width:200px">
  <p class="tracking-center inline-flex" style="padding:0 2em;">
    <span>
     Hello
   </span>

  </p>
  <p class="tracking-center inline-flex" style="padding:0 2em;">
   <span>
     The quick brown fox jumps over the lazy dog
   </span>
  </p>
</div>

<h3>Example: Container too narrow</h3>
<div style="width:20px; margin-left: 50px;">
  <p class="tracking-center">
    <span>
     Hello
   </span>
  </p>
  <p class="tracking-center">
   <span>
     The quick brown fox jumps over the lazy dog
   </span>
  </p>
</div>

<style>
<!-- example styles -->
div {
  border:2px cyan dotted;
}

p {
 border:2px pink dotted;
 display: inline-block;
}
p > span {
  background:white;
}
p {
  background:turquoise;
}
</style>

Upvotes: 0

Patrick Fisher
Patrick Fisher

Reputation: 8054

letter-spacing is inherently imbalanced, coming after each letter. You can compensate for it with a negative margin-right.

For example, in React with TypeScript and styled-components:

import React from 'react'
import styled from 'styled-components'

/**
 * Center text, accounting for letter-spacing.
 */
export const CenterText: React.FC<{
  className?: string
  letterSpacing: string
}> = ({ children, className, letterSpacing }) => {
  return <Body {...{ className, letterSpacing }}>{children}</Body>
}

/**
 * Negative right margin handles inherent imbalance in letter-spacing.
 * `justify-content: center` handles both narrow content and overflow.
 * `text-align: center` aligns multiple lines of text when text wraps.
 */
export const Body = styled.div<{ letterSpacing: string }>`
  display: flex;
  justify-content: center;
  letter-spacing: ${o => o.letterSpacing};
  margin-right: -${o => o.letterSpacing};
  text-align: center;
`

Upvotes: 1

Johnathan Evans
Johnathan Evans

Reputation: 1

The best answer I have found to solve a letter spacing word being off center is to simply put &nbsp; in front of the word.

Upvotes: 0

wrogn
wrogn

Reputation: 71

This behavior is because there is the extra space (as a result of increased letter spacing) added to the right side of the right most letter.

There is a simpler method to achieve center alignment in such cases. Just remove the letter spacing property from the last alphabet

Here is a solution.

div {
  width: 400px;
  height:400px;
  background-color: #3b0d3b;
  text-align:center;
  margin:auto;
}

p {
  color:#fff;
  margin-top: 40px;
  text-align:center;
  padding-top:30px;
  font-size: 1.2em;
}

.spacing {
  letter-spacing:.4em;
}

.spacing-large {
  letter-spacing:.9em;
}
<div>
  <p>- Foo Bar Zan -</p>
  <p class="spacing">- Foo Bar Zan <span style="letter-spacing:0">-</span></p>
  <p class="spacing-large">- Foo Bar Zan <span style="letter-spacing:0">-</span></p>
</div>

Notice the span element nesting the last character.

Upvotes: 0

rhodesit
rhodesit

Reputation: 41

Set a negative margin the same amount as the letter spacing. So if your letter spacing is 10px, set margin-right:-10px.

Using text-indent will leave that space in front of the first letter, even when the parent element is too small to fit the content, causing it to not look centered.

Upvotes: 2

Huangism
Huangism

Reputation: 16438

It seems you need to indent the text by the same amount as the letter-spacing. The first letter does not have the spacing applied to the left side

div {
  width: 400px;
  height: 400px;
  background-color: #3b0d3b;
  text-align: center;
  margin: auto;
}

p {
  color: #fff;
  background: black;
  text-align: center;
  font-size: 1.2em;
  padding: 0;
  margin: 0;
}

.spacing {
  letter-spacing: .4em;
}

.spacing-large {
  letter-spacing: 0.9em;
  text-align: center;
  text-indent: 0.9em;
}
<div>
  <p>- Foo Bar Zan -</p>
  <p class="spacing">- Foo Bar Zan -</p>
  <p class="spacing-large">- Foo Bar Zan -</p>
</div>

The logical explanation I came up with is - since it is the first letter, spacing on the left side will not apply.

Upvotes: 110

fidler2326
fidler2326

Reputation: 91

Using padding would be safer incase the text goes onto two lines. text-indent would only indent the first line of text.

p { 
  padding-left: 0.9em; 
}

Upvotes: 9

beautifulcoder
beautifulcoder

Reputation: 11330

If you look closely, the top one without letter spacing is not properly centered as well. The only thing I can think of is to monkey patch it with margin-left: 15px like so:

p { margin-left: 15px; }

Upvotes: 1

Related Questions