jumpy css font-size transition - html

Problem:
Hover cursor over the X and wait until the div is fully collapsed.
Move away from the X
Observe how div jumps to the bottom and straight back up.
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.
Can not disable wrapping on outer div ( except for during the animation ).
Can not add a fixed width or height to the inner div.
Can not use JS
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>

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>

.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.

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 is the variable content of the box
</div>

Related

Active tab border bottom under the div instead in the div

I have made a tab wrapper with 2 tabs. Under the tabs I have a div with content.
This is my code:
.tab-wrapper {
width: auto;
padding-left: 17px;
background-color: aqua;
white-space: nowrap;
display: table-cell;
}
.content {
background-color: aqua;
}
.role-tab {
cursor: pointer;
display: inline-block;
height: 50px;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
vertical-align: middle;
margin-right: 19px;
}
.role-tab>p {
display: table-cell;
height: 50px;
overflow: visible;
vertical-align: middle;
width: 100%;
}
.role-tab-active {
border-bottom: 3px #108DE7 solid;
font-weight: bold;
}
<div class="tab-wrapper">
<div class="role-tab role-tab-active">
<p>Role tab 1</p>
</div>
<div class="role-tab">
<p>Role tab 2</p>
</div>
</div>
<div class="content">
<p>Content</p>
</div>
The styling and everything are working good. Now I want to add some padding-top so the border-bottom will go under the div. This is a screenshot what I want:
I want that the border-bottom goes under the div instead of in the div.
I have tried margin-top, padding-top and top, but it didn't work
How can I achieve when the tab is active that the border-bottom goes under the div instead inside it?
just set the margin-bttom: -3px; for the active class and its done :
.role-tab-active {
margin-bottom:-3px;
border-bottom: 3px #108DE7 solid;
font-weight: bold;
}
see below snippet :
.tab-wrapper {
width: auto;
padding-left: 17px;
background-color: aqua;
white-space: nowrap;
display: table-cell;
}
.content{
background-color: aqua;
}
.role-tab {
cursor: pointer;
display: inline-block;
height: 50px;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
vertical-align: middle;
margin-right: 19px;
margin-bottom:-3px;
}
.role-tab > p {
display: table-cell;
height: 50px;
overflow: visible;
vertical-align: middle;
width: 100%;
}
.role-tab-active {
margin-bottom:-3px;
border-bottom: 3px #108DE7 solid;
font-weight: bold;
}
<div class="tab-wrapper">
<div class="role-tab role-tab-active">
<p>Role tab 1</p>
</div>
<div class="role-tab">
<p>Role tab 2</p>
</div>
</div>
<div class="content">
<p>Content</p>
</div>
You can't move borders via padding and margin. It's not an element but part of the element.
Give the .tab-wrapper a static height instead of default auto. Whatever the size of your border, the containing div will adjust to it instead, so we give it a static height to allow overflow. And then make it display:flex.
.tab-wrapper {
width: auto;
padding-left: 17px;
background-color: aqua;
white-space: nowrap;
display: flex;
height: 50px;
}
You can see that both the parent and tab items are of 50px height, but that's not really the case when rendered. box-sizing: content-box being the default css property, your official active role tab height is 53px, thus, overflowing the div by 3px and giving the border an "under the div" effect
Fiddle: https://jsfiddle.net/c5u3wzv2/5/

Overflow clipped, rest of the content visible

Considering the following DOM distribution. I have a flexbox container with two children, one of them has a fixed size while the other shrinks with an overflow: hidden. I was wondering, however, if there is a way for the overflown content to remain visible without any impact on the flow of the DOM.
Fleshed out Example at Codepen
ul.current {
list-style: none;
display: flex;
width: 40%;
margin: 0 auto;
}
li {
overflow: hidden;
}
li:last-child {
flex-shrink: 0;
}
li div {
border: 1px solid black;
background: green;
width: 10rem;
height: 10rem;
}
li:last-child {
margin-top: 2rem;
}
li:last-child div {
background: red;
}
/* GOAL */
section {
margin: 0 auto;
width: 40%;
}
.item {
position: absolute;
}
.item:last-child {
margin-top: 2rem;
margin-left: 5rem;
}
.content {
border: 1px solid black;
background: green;
width: 10rem;
height: 10rem;
}
.item:last-child .content {
background: red;
}
<h3>Shrink the viewport to get an idea of what's the intended scenario</h3>
<ul class="current">
<li><div></div></li>
<li><div></div></li>
</ul>
<h3>Visual representation of the overlap behavior</h3>
<section>
<div class="item"><div class="content"></div></div>
<div class="item"><div class="content"></div></div>
</section>
What I want, basically, is for the images to "overlap" each other in a flexible context, meaning, a solution that would work on N cases.
Your issue may be more clear to resolve if you didn't use quite as much inline style. I added classes and css to your code to make it easier to read.
By adding flex-wrap:wrap; to the display:flex; on the section, the images wrap. I set the images to background-images, and the bg-size to cover. If you wish the first-listed image to display second, simply switch the divs.
Hope this helps
#imagedisp {
display: flex;
flex-wrap: wrap;
}
#div1 {
flex-shrink: 1;
/* overflow: hidden;*/
border: 1px dashed;
background-image: url("https://s3-media4.fl.yelpcdn.com/bphoto/xFlymSQW0weBqXjwZM6Y2Q/ls.jpg");
}
#div2 {
margin-bottom: 40px;
border: 1px dashed;
background-image: url("https://s3-media3.fl.yelpcdn.com/bphoto/_-U30Zk2XbUKe2fcdtEXLQ/o.jpg");
}
#div1,
#div2 {
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
}
div {
min-width: 300px;
/*width:300px;*/
height: 100px;
}
<section id="imagedisp">
<div id="div1">
<!-- <img />-->
</div>
<div id="div2">
<!-- <img />-->
</div>
</section>
In order to have an overlap you have to either use positioned elements (which is not the best solution if you want to keep the element in-flow) or use negative margin.
Let's consider negative margin. The trick is to find a way to adjust the margin in order to create the overlap when the parent container will shrink.
Here is a basic example:
section {
max-width: 300px;
border: 1px solid;
animation:change 2s linear infinite alternate;
}
#keyframes change {
from {max-width: 300px;}
to {max-width: 100px;}
}
.item{
height: 80px;
min-width: 80px;
background:blue;
display: inline-block;
vertical-align:top;
margin-right:calc((100% - 200px)/2);
}
.item:last-child {
margin-top: 2rem;
background: red;
}
<section>
<div class="item">
</div>
<div class="item">
</div>
</section>
As you can see, the trick is to define the margin considering the width of the container (100%) and we will have two cases:
When the width is bigger than Xpx we have a positive margin and a normal behavior with spacing
When the width is smaller than Xpx we will have a negative margin and will have the overlap effect without wrapping.
We need to simply find the good way to define the margin in order to obtain the needed behavior. We may also consider media query in case we want a different behavior like having no margin and then overlapping:
section {
border: 1px solid;
font-size:0;
}
.item{
height: 80px;
min-width: 80px;
background:blue;
display: inline-block;
vertical-align:top;
}
.item:nth-child(odd) {
margin-top: 2rem;
background: red;
}
#media all and (max-width:350px) {
.item{
margin-right:calc((100% - 320px)/4)
}
}
<section>
<div class="item">
</div>
<div class="item">
</div>
<div class="item">
</div>
<div class="item">
</div>
</section>
Another idea that work with nested element (like your intial code) is to keep the overflow visible and force the outer element to shrink using min-width:0.
ul.current {
list-style: none;
display: flex;
width: 40%;
margin: 0 auto;
animation:change 2s infinite linear alternate;
}
#keyframes change {
from {width:100%}
to {width:40%}
}
li {
min-width:0;
}
li div {
border: 1px solid black;
background: green;
width: 10rem;
height: 10rem;
}
li:nth-child(odd) {
margin-top: 2rem;
}
li:nth-child(odd) div {
background: red;
}
/* GOAL */
section {
margin: 0 auto;
width: 40%;
}
.item {
position: absolute;
}
.item:last-child {
margin-top: 2rem;
margin-left: 5rem;
}
.content {
border: 1px solid black;
background: green;
width: 10rem;
height: 10rem;
}
.item:last-child .content {
background: red;
}
<ul class="current">
<li><div></div></li>
<li><div></div></li>
<li><div></div></li>
<li><div></div></li>
</ul>

How to make some text overlap other text without position absolute

I have two text fields inside a 100% width flex row. One is positioned on the left and the other on the right. I want the text on the right to overlap/cover the text on the left when the container (window) is resized (smaller) from the right.
Solutions must not use absolute positioning. The left-text has a left margin that the right-text must stop at. The text container is purposefully a row of 100% width.
Fiddle is not the best platform for layout and resizing testing, but https://jsfiddle.net/Lcjcyp4g/6/
The position:abs solution is commented out in the flex code below for completeness. Please ignore the behavior on resize-right -- our only focus is text overlap on resize-left.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div class="container">
<div class="container--text">
<div class="left">Left Text</div>
<!-- <div class="container--right"> -->
<div class="right">Right Text</div>
<!-- </div> -->
</div>
</div>
</body>
</html>
html, body {
height: 100vh;
width:100%;
background-color: #D7CCC8;
overflow: hidden;
margin: 0;
padding: 0;
}
.container {
min-width:100%;
width:100%;
margin-left:20px;
height: 14px;
max-height:14px;
}
.container--text {
height: 14px;
max-height:14px;
width:100%;
display: flex;
flex-flow: row nowrap;
padding: 10px 0;
}
.left {
white-space: nowrap;
color: #000000;
font-size: 14px;
font-weight: bold;
text-overflow: ellipsis;
flex-shrink:1;
}
/* This is not a viable soln because there is no boundary left for the pos:absolute element without JS*/
.container--right {
/*height: 14px;
background-color: #D7CCC8;
position:absolute;
right:0;
*/
}
.right {
white-space: nowrap;
justify-self:flex-end;
margin-left:auto;
margin-right:20px;
background-color:#BCAAA4;
color: #616161;
font-size: 12px;
}
A solution is to add width: 0;min-width: 0; to the left text to make the left part with no size thus the text will overflow. Then due to white-space:nowrap you won't see any visual changes but the right text will be able to cover it.
html,
body {
margin: 0;
padding: 0;
}
.container--text {
display: flex;
flex-flow: row nowrap;
padding: 10px 0;
animation: change 2s infinite linear alternate;
}
.left {
white-space: nowrap;
width: 0;
min-width: 0;
color: #000000;
font-weight: bold;
}
.right {
white-space: nowrap;
margin-left: auto;
margin-right: 20px;
background-color: #BCAAA4;
color: #616161;
}
#keyframes change {
from{width:500px;}
to{width:230px;}
}
<div class="container--text">
<div class="left">Leeeeeeeeeeeft Text</div>
<div class="right">Rigggggggggggggggght Text</div>
</div>
Or you can omit the width:0 and use overflow:hidden to hide the text when its container will shrink:
html,
body {
margin: 0;
padding: 0;
}
.container--text {
display: flex;
flex-flow: row nowrap;
padding: 10px 0;
animation: change 2s infinite linear alternate;
}
.left {
white-space: nowrap;
overflow:hidden;
text-overflow:ellipsis;
min-width: 0;
color: #000000;
font-weight: bold;
}
.right {
white-space: nowrap;
margin-left: auto;
margin-right: 20px;
background-color: #BCAAA4;
color: #616161;
}
#keyframes change {
from { width: 500px;}
to { width: 230px; }
}
<div class="container--text">
<div class="left">Leeeeeeeeeeeft Text</div>
<div class="right">Rigggggggggggggggght Text</div>
</div>

CSS how to have position absolute child visible outside of parent with overflow: hidden;

I have a parent element .box with overflow: hidden;
I have a child element .segment which has an ::after
I need to position ::after outside of .box but still be able to see it even though .box is overflow: hidden;
<div class="box">
<div class="segment">
::after // This ::after is displayed outside of the parent but isn't visible because of `overflow: hidden;`
</div>
</div>
.box needs to be overflow: hidden; so that the parents border-radius is shown.
CSS for ::after
.segment::after {
content: '';
position: absolute;
top: -30px;
left: 0px;
width: 100%;
height: 30px;
background-color: ...
}
Here is JSFiddle: https://jsfiddle.net/o73ft5k2/
Does anyone know how I can keep overflow: hidden; so border radius works but also allow the ::after pseudo-element to appear outside of the parent?
You can't do it if the overflow:hidden is in place. There is a better way to achieve the same effect without using overflow:hidden as it is just not needed to achieve this effect. Check this updated jsfiddle:
https://jsfiddle.net/o73ft5k2/1/
You can simply apply border-radius on particular elements. Also, notice `box-sizing: border-box" on an after element as padding had to be added for the text to align properly.
As far as I'm aware, you can't. You would need to apply the border-radius to the elements instead of the parent in this case.
* {
padding: 0px;
margin: 0px;
}
body {
background: white;
padding: 40px;
}
.box {
display: inline-block;
height: 30px;
line-height: 30px;
/*border-radius: 30px;*/
color: white;
}
.segment {
position: relative;
display: inline-block;
width: 150px;
padding-left: 5px;
padding-right: 5px;
}
.segment:first-child, .segment:first-child:after {
border-radius: 30px 0 0 30px;
}
.segment:last-child, .segment:last-child:after {
border-radius: 0 30px 30px 0;
}
.red {
background: red;
}
.blue {
background: blue;
}
.segment:after {
content: '';
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 30px;
background-color: rgba(0, 0, 0, 0.5);
transition: top 0.3s;
}
.segment:hover::after {
content: 'hello world!';
color: white;
top: -30px;
}
<div class="box">
<div class="segment red">
curved border
</div>
<div class="segment blue">
hover broken
</div>
</div>

Animating Text Using CSS

How do you animate the text position smoothly. On hover, I want to re-position the text from text-align: center to text-align: left.
From this state:
To this state:
When I change the text-align on a :hover selector, the transition isn't smooth. It just jumps to the left alignment.
div.subject > div.subjectHeader {
height: 200px;
width: 100%;
color: white;
font-family: 'Lato', 'Helvetica', sans-serif;
font-weight: 700;
font-size: 1.8em;
box-sizing: border-box;
text-align: center;
vertical-align: middle;
line-height: 200px;
transition: all 0.7s cubic-bezier(0.4,0,0.2,1);
-moz-transition: all 0.7s cubic-bezier(0.4,0,0.2,1);
}
div.subject:hover > div.subjectHeader {
height: 30px !important;
line-height: 30px !important;
font-size: 1.5em !important;
text-align: left !important;
padding-left: 10px !important;
}
Here is the jsfiddle: Link to jsfiddle
The text-align property is not animatable, so CSS transitions will not be applied to it.
One possible workaround involves positioning your text inside a div absolutely and animating the left property instead. For example, modify your header HTML like this:
<div class="subjectHeader"><span class="subjectHeaderInner>Chemistry</span></div>
Then animate the CSS of .subjectHeaderInner using the left and margin properties. Don't change text-align as there's no way to animate that property. For example:
div.subject .subjectHeaderInner {
width: 200px;
position: absolute;
left: 50%;
margin-left: -100px;
-moz-transition: all 0.7s cubic-bezier(0.4, 0, 0.2, 1);
}
div.subject:hover .subjectHeaderInner {
left: 0;
margin-left: 0;
}
I updated your fiddle with this code: http://jsfiddle.net/kAPtL/5/
Other workarounds are possible depending on what kind of effect you want. There are some examples at Is it possible to transition text-alignment using CSS3 only?
Edit: Slightly better, since the closing animation can't be done with precision (without knowing the text length), I made it simpler but at least it doesn't look that bad.
This is an alternative that works pretty well, almost perfect I would say. The most notable trick is using white-space: nowrap to play with the box dimensions effectively.
HTML layout:
<div>
<h1>
<span>Some Title</span>
</h1>
<p>some cool explanation</p>
<p>more explanation</p>
</div>
CSS that delivers the magic:
div { border: 5px solid black; height: 18em; padding-top: 2em; position: relative; width: 20em; }
div:hover h1 { height: 1.2em; }
div:hover span { right: 10em; padding-top: 0; }
h1 { bottom: 0; height: 20rem; margin: 0; top: 0; width: 20rem; }
p { padding: 10px; }
span { font-size: 1em; left: 0; padding-top: 4em; position: absolute; right: 0; text-align: center; white-space: nowrap; }
h1, span { background: green; position: absolute; transition: all .3s ease; }
JSFiddle example