1

Say I have some HTML like this:

<h1>The is a very long title, on small screens it will wrap but not on wider screens</h1>

I want to make the text-align property to center when it's on very large screens and left on smaller ones. Is there any pure CSS way to detect if the text will wrap?

starball
  • 20,030
  • 7
  • 43
  • 238
AGamePlayer
  • 7,404
  • 19
  • 62
  • 119
  • 2
    Are you wanting a completely gerneral solution - i.e. can the problem be stated as 'If the text will fit on one line then it should be centered on the screen and if it needs to wrap then it must be left aligned'? – A Haworth Feb 24 '23 at 07:15
  • yes, something like that. You are correct. – AGamePlayer Feb 24 '23 at 11:52

1 Answers1

2

As far as I know (and I may very well be wrong), no. You can't detect whether a line will wrap with CSS alone.

I can't think of a way to do it without JavaScript without some temporary flashes of ugliness either:

To check if a block element will wrap with JavaScript, you could do something like this, which basically temporarily forces the element to have no text wrapping, and then checks its calculated / rendered size and compares it to the width its parent element would have (and does some other checks on how text flows and sizings happen according to the parent element):

function checkWillOverflow(elem) {
  const parent = elem.parentElement;
  const parentStyleMap = parent.getComputedStyleMap();
  if (parentStyleMap.get("width").value === "max-content") {
    return false;
  }
  if (parentStyleMap.get("overflow-x").value === "scroll") {
    return ; // TODO: you need to decide what you want to happen here.
  }

  // this function assumes there is nothing in the style attributes to overwrite
  // (and that anything it takes higher precedence over is in style rules).
  // if there is, you will need to "back up" those values and restore them after.
  elem.style.width = "max-content";
  // set border and padding of parent to empty in preparation to get the
  // calculated width of the content box only.
  parent.style.borderWidth = "0";
  parent.style.padding = "0";

  const willOverflow = elem.getBoundingClientRect().width > parent.getBoundingClientRect().width;

  // undo the style attribute changes
  parent.style.removeProperty("border-width");
  parent.style.removeProperty("padding");

  return willOverflow;
}

You might also want to check the computed style maps to do something different if the writing-mode is a top-bottom one (or you might not).

If you (or someone else reading this) don't actually care whether it will wrap and actually just want different styles based on things like viewport width, check out CSS' media queries feature.

If you want to be updated on changes to the sizing of the element in question, you will need to use the ResizeObserver API.

starball
  • 20,030
  • 7
  • 43
  • 238