Willem D'Haeseleer
Willem D'Haeseleer

Reputation: 20180

jumpy css font-size transition

Problem:

Question:

How can I make the div expand without the font wrapping during the animation. ( I'm using a delayed font-size now, which seems to be problematic ).

Constrains:

These constrains are in effect due to the broader design of this isolated snippet.

More context:

I'm using white-space:nowrap for the hover state so the text doesn't wrap while the div collapses. I then use a delayed font-size transition to prevent the text from wrapping while the div expands again ( since it's not possible to animate white-space or display ). It seems like somehow the font-size of 0 get's lost for a fraction of a second at the beginning of the animation or something. Not sure exactly why it's jumping in the beginning.

.outer {
  width: 300px;
  overflow: hidden;
  border: 1px solid red;
  transition: width 2s;
}

.button {
  padding: 0px 10px;
  display:inline-block;
}

.outer:hover {
  width: 30px;
  white-space: nowrap;
}
.outer .inner {
  font-size: 15px;
  display:inline-block;
  transition: font-size 0s 2s;
}

.outer:hover .inner {
  font-size: 0px;
}
<div class="outer">
<div class="button">
X
</div>
<div class="inner"> 
This is the variable content of the box
</div>
</div>

Upvotes: 1

Views: 4024

Answers (3)

Michael Mano
Michael Mano

Reputation: 3440

.outer {
  width: 300px;
  overflow: hidden;
  border: 1px solid red;
  transition: width 2s;
}
.button {
  padding: 0px 10px;
  display: inline-block;
  float: left;
  line-height: 1;
}
.outer:hover {
  width: 30px;
  white-space: nowrap;
}
.outer .inner p {
  font-size: 15px;
  display: inline-block;
  float: left;
  transition: all ease-in-out 2s;
  line-height: 1;
  margin: 0;
}
.outer:hover .inner p {
  font-size: 0px;
  transition: all ease-in-out 1s;
}
<div class="outer">
  <div class="button">
    X
  </div>
  <div class="inner">
    <p>This is the variable content of the box</p>
  </div>
</div>

target the p, change the transition to all.

Upvotes: 2

TheThirdMan
TheThirdMan

Reputation: 1522

This is one of the problems you get when you change an object's size on hovering over itself. The trick to solving this is to use a parent container to hover on, which will always cover the width of the element, causing a slight ghosting effect, but compared to the visual effects your original solution had, this is much cleaner.

Your list of constraints isn't easy to work with, and the only way I can see this being solved under these circumstances is by making button and element that doesn't interfere with the document flow inside your container, so that nothing will wrap. Here are a few different attempts, one of which hopefully suiting your requirements:

solution fitting all contraints, using white-space

.outer-wrapper {
  width: 350px;
}
.outer {
  width: 350px;
  overflow: hidden;
  border: 1px solid red;
  transition: width 2s;
}
.button {
  width: 0;
  height: 0;
}
.button:after {
  content: 'X';
  padding: 0px 10px;
  display: inline-block;
}
.outer-wrapper:hover .outer {
  width: 30px;
}
.outer .inner {
  font-size: 15px;
  display: inline-block;
  margin-left: 2em;
  transition: font-size 0s 2s;
  white-space: nowrap;
}
.outer-wrapper:hover .outer .inner {
  font-size: 0px;
}
<div class="outer-wrapper">
  <div class="outer">
    <div class="button"></div>
    <div class="inner">
      This is the variable content of the box
    </div>
  </div>
</div>


solution fitting all contraints, changing the markup to use pre

This solution introduces a pre element, which will prevent wrapping on it's own because it inherits a white-space:pre declaration from it's default style.

.outer-wrapper {
  width: 350px;
}
.outer {
  width: 350px;
  overflow: hidden;
  border: 1px solid red;
  transition: width 2s;
}
.button {
  width: 0;
  height: 0;
}
.button:after {
  content: 'X';
  padding: 0px 10px;
  display: inline-block;
}
.outer-wrapper:hover .outer {
  width: 30px;
}
.outer .inner {
  font-size: 15px;
  display: inline-block;
  margin-left: 2em;
  transition: font-size 0s 2s;
}
.outer-wrapper:hover .outer .inner {
  font-size: 0px;
}
pre {
  font-family: inherit;
  margin: 0;
}
<div class="outer-wrapper">
  <div class="outer">
    <div class="button"></div>
    <div class="inner">
      <pre>This is the variable content of the box</pre>
    </div>
  </div>
</div>


hacking your way out

You need to prevent the inner div's contents from wrapping, and if you don't want to do this via white-space, the only option left is to replace all whitespaces in it with non-breaking spaces to make sure the element can't wrap anymore:

<div class="inner">
  This&nbsp;is&nbsp;the&nbsp;variable&nbsp;content&nbsp;of&nbsp;the&nbsp;box
</div>

Upvotes: 1

Rounin
Rounin

Reputation: 29463

You can:

  • add line-height: 22px; to .outer .inner; and
  • add height: 22px; to .outer.

.outer {
  width: 300px;
  height: 22px;
  overflow: hidden;
  border: 1px solid red;
  transition: width 2s;
}

.button {
  padding: 0px 10px;
  display:inline-block;
}

.outer:hover {
  width: 30px;
  white-space: nowrap;
}
.outer .inner {
  font-size: 15px;
  line-height: 22px;
  display:inline-block;
  transition: font-size 0s 2s;
}

.outer:hover .inner {
  font-size: 0px;
}
<div class="outer">
<div class="button">
X
</div>
<div class="inner"> 
This is the variable content of the box
</div>
</div>

Upvotes: 3

Related Questions