Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

text-transform capitalize css not working correctly

I've noticed a very strange problem when trying to style the navigation elements using the "text-transform: capitalize" css in my react project. It seems that React only applies the style to the first anchor tag and ignore the rest. However, everything works correctly with value set to "lowercase" or "uppercase".

Is this a known bug or it is intended?

here is the codepen to demostrate the Problem

Edit l4lnmvznvm

like image 436
York Wang Avatar asked Apr 11 '18 20:04

York Wang


People also ask

Why text-transform capitalize is not working?

Capitalize only affects the first letters of words. It will not change the case of the rest of the letters in a word. For example, if you capitalize a word that's in all capital letters already, the other letters in the word won't switch to lowercase.

How do you change text capitalization in CSS?

To make a block of text have all capital letters, use text-transform: uppercase in your CSS selector: text-transform: uppercase; The text-transform property accepts three possible values: uppercase: Sets each word to uppercase in a text element.

Can the text be capitalized using CSS?

The text-transform CSS property specifies how to capitalize an element's text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

How do I make uppercase text capitalized in CSS?

The CSS text-transform Property uppercase: makes all of the letters in the selected text uppercase or ALL CAPS. capitalize: capitalizes the first letter of each word in the selected text. none: leaves the text's case and capitalization exactly as it was entered.


1 Answers

Update

(and correct answer - what's below the line is only left as reference, providing context to the discussion on Chromium forum, as this issue was initially posted as a browser bug).

Although it might look like a bug, the implementation is correct. It's a feature. In short, any display:inline element is a "letter" in document's flow. If you decide not to put any space (or anything that might be interpreted as a space) between your letters, text-transform:capitalize should only capitalize the first letter in your "word".

To fix it, either give your links display:inline-block or add a pseudo (:before or :after) with display:inline-block;content:'';


Previous update:

TL,DR;

nav a:before {
  content: '​'; /* copy-paste a zero-width-space (​) character */
}

... or simply prefixing your anchor texts with ​ seems to fix the problem.
But, to be clear about it, the above is a hack. A workaround.

Another fix is to set nav a's display property to anything except inline, which is default — yes, display:none; fixes it, too. For good! ツ...
...which leads to a third option, even less intrusive and not needing chars playing hard-to-get:

nav a:before {
  content: ''; /* empty string, no specials here */
  display: inline-block;
}

Also works if used on nav a:after, if you need the :befores. What fixes it is breaking the continuous inline flow of the line.


Updated answer:

It looks like you found yourself a bug, which is currently present in both Chrome and Firefox. I haven't yet tested other browsers, but I'm expecting to experience this in the other webkit based browsers (Safari, Edge, Opera). I've filed the bug with Chromium which will, most likely, produce a fix for it in Chrome and, after a short while, in Firefox.

As suspected before you added the mcve, it's not related to React. I can reproduce it here, using simple markup:

nav a {
   margin: 1em;
   text-transform: capitalize;
}
<div><nav><a href="/">home</a><a href="/2">page 2</a><a href="/3">page 3</a></nav><div>

The most weird thing about it is... if you place each element on a different line (in markup)... it starts working properly, without any other change.

nav a {
   margin: 1em;
   text-transform: capitalize;
}
<div><nav><a href="/">home</a>
<a href="/2">page 2</a>
<a href="/3">page 3</a></nav><div>

Which led me to try out adding a zero-width-space &#8203; at the start of each anchor which, apparently, also fixes the problem:

nav a {
  margin: 1em;
  text-transform: capitalize;
}
nav a:before {
  content: '​';
}
<div><nav><a href="/">home</a><a href="/2">page 2</a><a href="/3">page 3</a></nav><div>

To apply the fix to your example, place this line before your <nav>:

<style>nav a:before{'{'}content:'&#8203;'{'}'}</style>

But still, it's a standing bug in Chrome and should be reported on their forum (and fixed).


Initial answer (before seeing the example)

React is JavaScript.

text-transform: capitalize;

... is CSS. If React handled it, the text would have been transformed before being placed in markup. The whole point of text-transform is to have the text unchanged in markup and rendered (by browser) transformed.

So your issue is not really a bug, and has nothing to do with React. It has to do with your browser not having implemented text-transform:capitalize yet. Or not applying it correctly.

See compatibility table here and here. Unfortunatelly, it's hard to determine (other than by trying them out yourself) browser support for a particular value of a partially supported property.

Until your browser supports it, you'll have to use React (or vanilla) or the library of your choice (i.e.: lodash has _.capitalize()) to capitalize your text.

And this simple example will tell you if your current browser supports it:

capitalize-meh {
  text-transform: capitalize;
}
<capitalize-meh>i should be capitalized...</capitalize-meh>

The only way to "fix" this in browser that don't have CSS support for capitalize is to define your own function:

capitalize(string) {
  return string.toLowerCase().replace(/(^|\s)\S/g, l => l.toUpperCase())
}

Test:

class TextExample extends React.Component {
  constructor(props) {
    super(props);
    this.text = props.text || '';
  }

  capitalize(string) {
    return string.toLowerCase().replace(/(^|\s)\S/g, l => l.toUpperCase())
  }

  render() {
    return (<text>{this.capitalize(this.text)}</text>);
  }
}
ReactDOM.render(
  new TextExample({text:'what eVaH...'}).render(),
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
like image 165
tao Avatar answered Oct 12 '22 23:10

tao