Incorrect transform position in Chrome when using percent - css

When using transform with percent value on container that has float width (for ex. 800.63px) Chrome always rounds position in pixels incorrectly.
This typically happens with em/rem width in combination with percent (see example below):
HTML:
<div class="container">
<div class="wrap">
<div class="slider">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
</div>
SCSS:
.container {
width: 38rem;
}
.wrap {
width: 33%;
overflow: hidden;
}
.slider {
white-space: nowrap;
font-size: 0;
transform: translate3d(-1000%,0,0);
}
.item {
display: inline-block;
height: 8rem;
width: 100%;
background: limegreen;
&:nth-child(even) {
background: orangered;
}
}
The result is some part of next slide is always visible. Looks like Chrome first rounds the item width and then multiplies it by percent value.
Is there any known workaround for this? If I do the math in JS and use px values in transform then everything is (almost) perfect, but shouldn't it "just work" with percents too?
Please, see fiddle for working example: https://jsfiddle.net/Lumh07te/37/

Change the way you set your sizes.
Instead of the slider having width 100%, and needing a maximum transform of 1000%, set it to a width of 1000%, and a needed maximum transform of 100%.
And the items width is now 10% instead of 100%
in your original code, wrap has a width that is not integer, but than in the layout is forced to render as an integer value in pixels. Then , translating a 1000% of this value multiplies the rounding errors by 10. If you instead set the width to 1000%, the rounding to pixels is done on this size, and then it is mutiplyed by values less than 1 (0.5, 0.6, 0.7.. ) or 1 at a maximum
.container {
width: 38rem;
}
.wrap {
width: 33%;
overflow: hidden;
}
.slider {
width: 1300%;
white-space: nowrap;
font-size: 0;
transform: translateX(calc(-500% / 13));
transition: transform 0.4s;
}
.test {
height: 50px;
}
.test:hover ~ .wrap .slider {
transform: translateX(calc(-800% / 13));
}
.item {
display: inline-block;
height: 8rem;
width: calc(100% / 13);
background: limegreen;
font-size: 30px;
}
.item:nth-child(even) {
background: orangered;
}
<div class="container">
<div class="test">test</div>
<div class="wrap">
<div class="slider">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
<div class="item">13</div>
</div>
</div>
</div>

Related

Flex: How do I set items to take up MAX 1/3 of their container, unless their content overflows

Let's say I have a flex container, I want to be display between 1 and 3 items within.
I would like the items to be:
By default 1/3 of the width of the container (even if there's only 1 item)
If one of the item's text content expands slightly beyond the 33% width, I'd like that item to try and expand if it can (i.e. by one of the other items shrinking).
Justified using flex-start
.container {
display: 'flex';
flex-direction: 'row';
background-color: 'red';
width: '100%';
justify-content: 'flex-start';
}
.item {
flex: 1;
border: 1px solid red;
flex-wrap: 'no-wrap';
}
<div class="container">
<div class="item">blahhhhhhhhhhhhhhhhhhhhhhhhhh</div>
<div class="item">blahhh</div>
<div class="item">blahhh</div>
</div>
<div class="container">
<div class="item">I should take up 1/3</div>
</div>
The above works for the 3 item case, however when a singular item is placed there it expands to fill the space.
Is this possible?
You can use CSS-Grid for that.
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
margin-bottom: 1em;
}
.item {
height: 50px;
border: 1px solid red;
}
.item.wide {
width: 250px;
}
<div class="container">
<div class="item wide"> I'm wider than 1/3</div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="container">
<div class="item"></div>
</div>
<div class="container">
<div class="item"></div>
<div class="item"></div>
</div>

Prevent contenteditable (in flexed div) from expanding [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 5 years ago.
I'm starting with css flex and I have a hard time with using a contenteditable that I can't prevent from expanding horizontally when the text is too long.
I tried on:
- Chrome
- Firefox
- Opera
- Safari
They all make the divs expand but Safari, who does what I expect.
Here is the HTML:
<div class="container">
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
</div>
Here is the CSS:
.container
{
width: calc(100% - 34px);
height:185px;
margin-left:17px;
margin-top:17px;
display:flex;
}
.column{
flex:1;
height:186px;
margin-right:1.75%;
}
.column:nth-child(5){
margin-right:0px;
}
.field{
margin-bottom:5px;
display:flex;
width:100%;
}
.field_left{
width:6px;
height:24px;
background:green;
}
.field_middle{
height:24px;
background:red;
width:calc(100% - 13px);
}
.field_right{
width:7px;
height:24px;
background:blue;
}
[contenteditable]
{
display:inline;
white-space: nowrap;
overflow:hidden;
text-overflow: inherit;
-webkit-user-select: auto;
user-select: auto;
-moz-user-select: -moz-text;
}
Of course, the HTML could be less complicated for such a result (divs into divs into divs) but keep in mind that I cleaned the code as much as possible in order to present it to you as the design asks for this.
However, I decided to show the relevant part of structure as it might be important to fix the problem.
Here is a JSFiddle of the result:
https://jsfiddle.net/b4er9tLg/2/
If you type a text into one of these boxes, when the text is long enough, it will expand its containing div and change the overall layout of the page.
(if it doesn't do that on your browser, then your browser is one of the happy few).
Basically, what I need is to get something like a hidden overflow on all browsers of text written so that the overall design won't break.
I just can't get it to work.
Thanks for your help.
You have given .column the property flex: 1. From the spec
w3
flex: <positive-number>
Equivalent to flex: <positive-number> 1 0. Makes the flex item flexible and sets the flex basis to zero, resulting in an item that
receives the specified proportion of the free space in the flex
container. If all items in the flex container use this pattern, their
sizes will be proportional to the specified flex factor.
To prevent column and it's contents from expanding you need to give it a max-width value.
I would also suggesting removing margin-right from .column. Instead, set the column width and use the justify-content property on the container.
fiddle
.container {
width: calc(100% - 34px);
height: 185px;
margin-left: 17px;
margin-top: 17px;
display: flex;
justify-content: space-between;
}
.column {
flex: 1;
height: 186px;
max-width: 19%;
}
.field {
margin-bottom: 5px;
display: flex;
width: 100%;
}
.field_left {
width: 6px;
height: 24px;
background: green;
}
.field_middle {
height: 24px;
background: red;
width: calc(100% - 13px);
}
.field_right {
width: 7px;
height: 24px;
background: blue;
}
[contenteditable] {
display: inline;
white-space: nowrap;
overflow: hidden;
text-overflow: inherit;
-webkit-user-select: auto;
user-select: auto;
-moz-user-select: -moz-text;
}
<div class="container">
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
</div>

Gutter between DIVs using negative margin breaks

I have the below code, which works fine. As you can see, it creates a gutter between the 3 green elements, which are children of the second out of three blue elements.
.container{
font-size: 0;
}
[class|="col"] {
display:inline-block;
vertical-align: top;
position:relative;
font-size:20px;
}
.col-1-3{
width:calc(100%/(3/1));
}
.col-2-3{
width:calc(100%/(3/2));
}
.col-1{
width:100%;
}
.children-has-gutters{
margin-left:-15px;
margin-right:-15px;
width: calc((100% / (3/1)) + 30px);
}
.children-has-gutters > div{
padding-left:15px;
padding-right:15px;
box-sizing: border-box;
}
.bg-blue{
background-color:#42a5f5;
color:#ffffff;
}
.bg-green{
background-color:#66bb6a;
color:#ffffff;
}
<div class="container">
<div class="col-1-3 bg-blue">blue left</div>
<div class="col-1-3 children-has-gutters" style="font-size:0px;">
<div class="col-1-3">
<div class="bg-green">green 1</div>
</div>
<div class="col-1-3">
<div class="bg-green">green 2</div>
</div>
<div class="col-1-3">
<div class="bg-green">green 3</div>
</div>
</div>
<div class="col-1-3 bg-blue">blue right</div>
</div>
In the below example, there is only one blue element, not three. And suddenly, the gutter between its green child elements doesnt work as expected. Sure, it has space in between, but it creates a horizontal scroller on the page, and the left most and right most side get the gutter as well, somehow seem like the negative margin doesnt work.
I would be grateful if someone could point out what breaks compared to the above code.
.container{
font-size: 0;
}
[class|="col"] {
display:inline-block;
vertical-align: top;
position:relative;
font-size:20px;
}
.col-1-3{
width:calc(100%/(3/1));
}
.col-2-3{
width:calc(100%/(3/2));
}
.col-1{
width:100%;
}
.children-has-gutters{
margin-left:-15px;
margin-right:-15px;
width: calc(100% + 30px);
}
.children-has-gutters > div{
padding-left:15px;
padding-right:15px;
box-sizing: border-box;
}
.bg-blue{
background-color:#42a5f5;
color:#ffffff;
}
.bg-green{
background-color:#66bb6a;
color:#ffffff;
}
<div class="container">
<div class="col-1 bg-blue children-has-gutters" style="font-size:0px;">
<div class="col-1-3">
<div class="bg-green">green 1</div>
</div>
<div class="col-1-3">
<div class="bg-green">green 2</div>
</div>
<div class="col-1-3">
<div class="bg-green">green 3</div>
</div>
</div>
</div>
So, color wise it should go: left edge of screen, green 1, blue gap, green 2, blue gap, green 3, right edge of screen.
This is just an example, the number of children can change, so its not always 3.
This question is a follow up question to an old question of mine, as I now found this bug and cant figure out the problem:
old question here >>
Requirements: I dont want to add new div elements, and I dont want to change to flexbox.
It's an ugly hack, but you could put overflow hidden on your container to get rid of the blue on the edges:
.container{
font-size: 0;
overflow: hidden;
}
I just don't see any reason for the negative margins and the calc width for the class ...has-gutters what you can do is just add a padding-right except for the last-child
.container {
font-size: 0;
}
[class|="col"] {
display: inline-block;
vertical-align: top;
position: relative;
font-size: 20px;
}
.col-1-3 {
width: calc(100%/(3/1));
}
.col-2-3 {
width: calc(100%/(3/2));
}
.col-1 {
width: 100%;
}
.children-has-gutters>div {
padding-right: 30px;
box-sizing: border-box;
}
.children-has-gutters>div:last-child {
padding-right:0;
}
.bg-blue {
background-color: #42a5f5;
color: #ffffff;
}
.bg-green {
background-color: #66bb6a;
color: #ffffff;
}
<div class="container">
<div class="col-1 bg-blue children-has-gutters" style="font-size:0px;">
<div class="col-1-3">
<div class="bg-green">green 1</div>
</div>
<div class="col-1-3">
<div class="bg-green">green 2</div>
</div>
<div class="col-1-3">
<div class="bg-green">green 3</div>
</div>
</div>
</div>

How do I split a 1170 pixels grid into 8 boxes?

I need to split a 1170 grid into 8 boxes of X each with each box having the same amount of padding on the left and right. I can't seem to get it right :(
I managed to do 134 x 8 pixels and then a gutter of 14 each but that doesn't work because then the first and last box wouldn't have the same padding.
You could try calc
padding: 7px;
width: calc(12.5% - 14px);
More on Calc at W3Schools.com
If you are able to use flexbox, you can get even spacing in only a few lines instead of calculating by hand. The best resource I've found for flexbox is https://css-tricks.com/snippets/css/a-guide-to-flexbox/
.container {
width: 1170px;
display: flex;
justify-content: space-between;
}
.item {
border: 2px solid red;
width: 50px;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
As commented, flex makes it easy.
+ selector will help to manage visually even padding
.flex {
display:flex;/* block level */
width:1170px;/* any values here or none */
height:100px;/* whatever: demo purpse*/
margin:auto;
background:lightgray;/* whatever: demo purpse*/
}
.flex div {
flex:1;/* sprays child evenly to fill whole space*/
padding:1em;
background:gray;
background-clip:content-box;/*show box minus padding area */
}
.flex div + div {/* make padding visually even */
padding-left:0;
}
div div {
display:flex;
align-items:center;
justify-content/* it's not text-align*/:center;
}
/* not just sure if that would be fine ? */
.flex:hover div {
padding:21px;
box-shadow:0 0 0 1px white
}
<div class=flex>
<div>average 128px each</div>
<div>width for content</div>
<div>is less or more</div>
<div>according to font-size</div>
<div>padding is 1em</div>
<div>but could be</div>
<div>static units</div>
<div>such as pixels</div>
</div
you do not want to use flex because you (unfortunate you) run IE8 ? display:table + table-layout:fixed will do the job for you
.flex {
display: table;
/* block level */
table-layout: fixed;
/* sprays child evenly if no width is specified*/
width: 1170px;
/* any values here or none */
height: 100px;
/* whatever: demo purpse*/
margin: auto;
background: lightgray;
/* whatever: demo purpse*/
}
.flex div {
display: table-cell;
padding: 1em;
background: gray;
background-clip: content-box;
/*show box minus padding area */
}
.flex div + div {
/* make padding visually even */
padding-left: 0;
}
div div {
vertical-align:middle;
text-align : center;
}
/* not just sure if that would be fine ? */
.flex:hover div {
padding: 21px;
box-shadow: 0 0 0 1px white
}
<div class=flex>
<div>average 128px each</div>
<div>width for content</div>
<div>is less or more</div>
<div>according to font-size</div>
<div>padding is 1em</div>
<div>but could be</div>
<div>static units</div>
<div>such as pixels</div>
</div
For some reason my jsFiddle here wouldn't work but I got eight columns working here: http://codepen.io/anon/pen/zoyEme
Make two half columns then put four columns in each of those for a total of eight.
Code:
.container,
.row,
.col-lg-6 {
padding-left: 0;
padding-right: 0;
}
div {border: 1px dotted red;}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container">
<div class="row">
<div class="col-lg-6">
<div class="col-lg-3">
ONE
</div>
<div class="col-lg-3">
ONE
</div>
<div class="col-lg-3">
ONE
</div>
<div class="col-lg-3">
ONE
</div>
</div>
<div class="col-lg-6">
<div class="col-lg-3">
ONE
</div>
<div class="col-lg-3">
ONE
</div>
<div class="col-lg-3">
ONE
</div>
<div class="col-lg-3">
ONE
</div>
</div>
</div>
</div>

Have div take up 1/6th of remaining parent div height

I am attempting to make a simple calendar using css.
I have a parent div that will contain the calendar, and I have a div within that that contains the header with "Monday", "Tuesday", etc and is of fixed height. I now want to add divs that represent the rows of the calendar and split the remaining space into six even rows. However, I can't figure out how to divide the REMAINING space into 6 parts. Everything I try makes the div 1/6th of the parent div.
Any tips would be appreciated.
HTML:
<div id="parent>
<div id="header">
ST
</div>
<div class="row">
hi
</div>
</div>
CSS:
.row{
width:100%;
height: 16.66%;
background-color:red;
}
When you want to distribute remaining space left by a flexible element, flexbox is the answer.
html, body, #parent {
margin: 0;
height: 100%;
}
#parent {
display: flex;
flex-direction: column;
}
#header {
background-color: green;
}
.row {
width: 100%;
flex: 1; /* Distribute remaining space equally among the rows */
background-color: red;
}
.row:nth-child(odd) {
background-color: blue;
}
<div id="parent">
<div id="header">Header</div>
<div class="row"></div>
<div class="row"></div>
<div class="row"></div>
<div class="row"></div>
<div class="row"></div>
<div class="row"></div>
</div>
There are several ways to do that, and to pick one I need to know more how it should be used.
This sample simply use CSS calc() and subtract 1/6 of the header from 1/6 of the parent.
html, body {
margin: 0;
}
#parent {
height: 100vh;
}
#header {
height: 60px;
background-color:green;
}
.row{
height: calc(16.66% - 10px);
background-color:red;
}
.row:nth-child(odd){
background-color:blue;
}
<div id="parent">
<div id="header">
Header
</div>
<div class="row">
</div>
<div class="row">
</div>
<div class="row">
</div>
<div class="row">
</div>
<div class="row">
</div>
<div class="row">
</div>
</div>

Resources