97

http://jsfiddle.net/nicktheandroid/tVHYg/

When hovering .wrapper, it's child element .contents should animate from 0px to it's natural width. Then when the mouse is removed from .wrapper, it should animate back down to 0px. The .wrapper element should only be as wide as it needs to be (allowing .contents to grow), so .wrapper should grow in width and shrink in width as .contents does. There should be no set width for .contents. I'm using CSS3, but it could be accomplished in jQuery, that would be fine.

The problem: See the JSfiddle

  1. .wrapper is not only as wide as it needs to be.
  2. when .contents grows, when it's almost at it's full width, it jumps down to the next line
  3. When hovering off of .wrapper, .contents vanishes, when it should animate down to 0px

.wrapper {
    display: inline-block;

    height: 20px;
    width: auto;
  
    padding:10px;
  
    background:#DDD;
}

.contents {
    display:inline-block;
  
    width:0%;
  
    white-space:nowrap;
    overflow:hidden;
  
    background:#c3c;
}

.wrapper:hover .contents {
    -webkit-transition: width 1s ease-in-out;
    -moz-transition: width 1s ease-in-out;
    -o-transition: width 1s ease-in-out;
    transition: width 1s ease-in-out;

    width:100%;
}
<div class="wrapper">
    <span>+</span>
    <div class="contents">These are the contents of this div</div>
</div>
Aleksander Azizi
  • 9,829
  • 9
  • 59
  • 87
android.nick
  • 11,069
  • 23
  • 77
  • 112

6 Answers6

93

I think I've got it.

.wrapper {
    background:#DDD;
    display:inline-block;
    padding: 10px;
    height: 20px;
    width:auto;
}

.label {
    display: inline-block;
    width: 1em;
}

.contents, .contents .inner {
    display:inline-block;
}

.contents {
    white-space:nowrap;
    margin-left: -1em;
    padding-left: 1em;
}

.contents .inner {
    background:#c3c;
    width:0%;
    overflow:hidden;
    -webkit-transition: width 1s ease-in-out;
    -moz-transition: width 1s ease-in-out;
    -o-transition: width 1s ease-in-out;
    transition: width 1s ease-in-out;
}



.wrapper:hover .contents .inner {
   
    width:100%;
}
<div class="wrapper">
    <span class="label">+</span>
    <div class="contents">
        <div class="inner">
            These are the contents of this div
        </div>
    </div>
</div>

Animating to 100% causes it to wrap because the box is bigger than the available width (100% minus the + and the whitespace following it).

Instead, you can animate an inner element, whose 100% is the total width of .contents.

bflemi3
  • 6,698
  • 20
  • 88
  • 155
eyelidlessness
  • 62,413
  • 11
  • 90
  • 94
  • 4
    SO close, the last thing to accomplish is getting `.wrapper` to get bigger and smaller in width as needed, I've been trying for a bit but I can't get it. This was #1 above in the list, maybe I didn't explain that one very well. So the wrapper should only be as big as the "+" with equal padding on all sides. Then `.wrapper` grows in width as `.contents` does. I thought this was going to be super simple to do, but I've had so much trouble with it. – android.nick Oct 22 '11 at 19:56
  • @android.nick this works like you want, BUT, i can't figure out the float/alignment part... you'll see: http://jsfiddle.net/wxh6kc71/ – MaxOvrdrv Apr 23 '15 at 18:44
  • 1
    @android.nick and lastly, here's one that also conforms to the width of the contents / expands the wrapper to the width of the contents... however, transitions on width MUST have a numerical value otherwise they don't animate. So unless you're willing to use JavaScript to make the animation, you're out of luck there. http://jsfiddle.net/62dtk8mg/ – MaxOvrdrv Apr 24 '15 at 12:23
  • But `.wrapper`'s width is not 0; `.wrapper`'s width is always of `.contents`'s width without any content inside. Not a big deal. How to make `.wrapper` grow and shrink along with `.contents`. With CSS only. That's the question! – Green Feb 02 '16 at 13:53
  • 2
    Here is a fork to make the text appear from right to left in case anybody wonders:) the trick is direction:rtl; http://jsfiddle.net/18astcoo/ – Fanky Aug 24 '16 at 16:09
  • I think the overflow: none; is what my css neeeded. – CDM social medias in bio Feb 17 '20 at 02:18
16

http://jsfiddle.net/tVHYg/5/

.wrapper {
    background:#DDD;
    padding:1%;
    display:inline;
    height:20px;
}


span {
    width: 1%;
}

.contents {
    background:#c3c;
    overflow:hidden;
    white-space:nowrap;
    display:inline-block;
    width:0%;
}



.wrapper:hover .contents {
    -webkit-transition: width 1s ease-in-out;
    -moz-transition: width 1s ease-in-out;
    -o-transition: width 1s ease-in-out;
    transition: width 1s ease-in-out;

    width:90%;
}
chovy
  • 72,281
  • 52
  • 227
  • 295
  • 1
    Almost, it should only animate to a width that is as wide as the content is, no more than that though. Getting all this to work perfectly is tougher than I thought. – android.nick Oct 22 '11 at 21:02
9

Got it to work by transitioning the padding as well as the width.

JSFiddle: http://jsfiddle.net/tuybk748/1/

<div class='label gray'>+
</div><!-- must be connected to prevent gap --><div class='contents-wrapper'>
    <div class="gray contents">These are the contents of this div</div>
</div>
.gray {
    background: #ddd;
}
.contents-wrapper, .label, .contents {
    display: inline-block;
}
.label, .contents {
    overflow: hidden; /* must be on both divs to prevent dropdown behavior */
    height: 20px;
}
.label {
    padding: 10px 10px 15px;
}
.contents {
    padding: 10px 0px 15px; /* no left-right padding at beginning */
    white-space: nowrap; /* keeps text all on same line */
    width: 0%;
    -webkit-transition: width 1s ease-in-out, padding-left 1s ease-in-out, 
        padding-right 1s ease-in-out;
    -moz-transition: width 1s ease-in-out, padding-left 1s ease-in-out, 
        padding-right 1s ease-in-out;
    -o-transition: width 1s ease-in-out, padding-left 1s ease-in-out, 
        padding-right 1s ease-in-out;
    transition: width 1s ease-in-out, padding-left 1s ease-in-out, 
        padding-right 1s ease-in-out;
}
.label:hover + .contents-wrapper .contents {
    width: 100%;
    padding-left: 10px;
    padding-right: 10px;
}
Chris Middleton
  • 5,654
  • 5
  • 31
  • 68
  • Wrapper has width. It occupies space anyway, even if there is no any content in it. – Green Feb 02 '16 at 14:31
  • @Chris Middleton, for kicks, I wanted to try this from right to left, but haven't come up with the correct way yet. – Chris22 Jan 06 '17 at 05:03
8

a late answer, but I think this one works as required in the question :)

this one uses z-index and position absolute, and avoid the issue that the container element width doesn't grow in transition.

You can tweak the text's margin and padding to suit your needs, and "+" can be changed to font awesome icons if needed.

body {
  font-size: 16px;
}

.container {
  height: 2.5rem;
  position: relative;
  width: auto;
  display: inline-flex;
  align-items: center;
}

.add {
  font-size: 1.5rem;
  color: #fff;
  cursor: pointer;
  font-size: 1.5rem;
  background: #2794A5;
  border-radius: 20px;
  height: 100%;
  width: 2.5rem;
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  z-index: 2;
}

.text {
  white-space: nowrap;
  position: relative;
  z-index: 1;
  height: 100%;
  width: 0;
  color: #fff;
  overflow: hidden;
  transition: 0.3s all ease;
  background: #2794A5;
  height: 100%;
  display: flex;
  align-items: center;
  border-top-right-radius: 20px;
  border-bottom-right-radius: 20px;
  margin-left: 20px;
  padding-left: 20px;
  cursor: pointer;
}

.container:hover .text {
  width: 100%;
  padding-right: 20px;
}
<div class="container">
  <span class="add">+</span>
  <span class="text">Add new client</span>
</div>
Roy.L.T
  • 153
  • 2
  • 5
2

Please check following snippet

 /* DEBUG */
.lwb-col {
    transition: box-shadow 0.5s ease;
}
.lwb-col:hover{
    box-shadow: 0 15px 30px -4px rgba(136, 155, 166, 0.4);
 
}


.lwb-col--link {
    font-weight: 500;
  position: relative;
  display: inline-block;
}
.lwb-col--link::after{
    border-bottom: 2px solid;
    bottom: -3px;
    content: "";
    display: block;
    left: 0;
    position: absolute;
    width: 100%;
    color: #E5E9EC;

}
.lwb-col--link::before{
    border-bottom: 2px solid;
    bottom: -3px;
    content: "";
    display: block;
    left: 0;
    position: absolute;
    width: 100%;
    color: #57B0FB;
    transform: scaleX(0);
    

}
.lwb-col:hover .lwb-col--link::before {
    border-color: #57B0FB;
    display: block;
    z-index: 2;
    transition: transform 0.3s;
    transform: scaleX(1);
    transform-origin: left center;
}
<div class="lwb-col">
  <h2>Webdesign</h2>
  <p>Steigern Sie Ihre Bekanntheit im Web mit individuellem &amp; professionellem Webdesign. Organisierte Codestruktur, sowie perfekte SEO Optimierung und jahrelange Erfahrung sprechen für uns.</p>
<span class="lwb-col--link">Mehr erfahren</span>
</div>
-2

I haven't been able to get it to work without specifying a width but the following css worked

.wrapper {
    background: #DDD;
    padding: 10px;
    display: inline-block;
    height: 20px;
    width: auto;
}

.contents {
    background: #c3c;
    overflow: hidden;
    white-space: nowrap;
    display: inline-block;
    visibility: hidden;
    width: 1px;
    -webkit-transition: width 1s ease-in-out, visibility 1s linear;
    -moz-transition: width 1s ease-in-out, visibility 1s linear;
    -o-transition: width 1s ease-in-out, visibility 1s linear;
    transition: width 1s ease-in-out, visibility 1s linear;
}

.wrapper:hover .contents {
    width: 200px;
    visibility: visible;
}

I'm not sure you will be able to get it working without setting a width on it.

Nalum
  • 4,143
  • 5
  • 38
  • 55