Percentages with SASS - one pixel problems? - css

I want to build my minimal CSS framework. I did a grid system in SASS:
$width: 960px;
width: $width;
.grid-12 { width: $width; }
.grid-11 { width: percentage((($width/12)*11)/$width) }
.grid-10 { width: percentage((($width/12)*10)/$width) }
.grid-9 { width: percentage((($width/12)*9)/$width) }
.grid-8 { width: percentage((($width/12)*8)/$width) }
.grid-7 { width: percentage((($width/12)*7)/$width) }
.grid-6 { width: percentage(($width/2)/$width) }
.grid-5 { width: percentage((($width/12)*5)/$width) }
.grid-4 { width: percentage(($width/3)/$width) }
.grid-3 { width: percentage(($width/4)/$width) }
.grid-2 { width: percentage(($width/6)/$width) }
.grid-1 { width: percentage(($width/12)/$width) }
It works great, but sometimes - in some resolutions, eg. at my mobile with landscape view (960x540) some elements are 1px too short. It happens also when I resize browser.
What can I do?

some of the calculations will result in a number that can NOT be divided by 2
sometimes you will get .5px ...
and because of this . you will sometimes have 1 extra pixel

There is no "fix" for this. That's the way it is with all responsive layouts and grid systems. There are techniques like float isolation that can help keep your rounding errors from multiplying. Otherwise, 10 1px errors can turn into a 10px error. I wouldn't use that everywhere, but it's useful if you have a gallery-style layout with a lot of elements, all the same size, floating next to each other.
The real solution, mentioned in a comment above, is to adjust your design so that 1px rounding errors don't matter. If 1px can ruin your layout, responsive design isn't going to work.
You can't eliminate the rounding errors, but you have some control over where the missing pixels should go. By floating things left or right, and nesting in different ways, you can move the rounding errors where they will be least noticeable. Another solution is to apply layout (instead of float/width) to the last element in a row, and it will expand to fill the remaining space. The easiest way to apply layout is with overflow: hidden;, but that has some drawbacks.

Related

How do I correctly use Media Query to cause one column to disappear and the other to adjust to the width of the screen?

In my class we are starting to use Media Queries and I am having a little trouble with an assignment. For a previous assignment we were tasked with remaking a website called "the Toast" as best we could, which I have here. Now for this assignment we are to use media query to do a few things:
This assignment is all about media queries and getting your site to be
responsive. We will be using the website The toast again for this
assignment. You will be laying out two columns for the content area.
When the screen size hits 960px the right column must disappear. The
articles in the left column must adjust to the width of the screen.
The images must get bigger and fill the article at 960 px as well.
At 760 px the support us button, love the toast text and the social
media must disappear.
In the code I have two columns, a "bigColumn" and a "adColumn". Now to my understanding to make the adcolumn disappear and adjust the bigColumn I simply have to add:
#media only screen and (max-width: 960px) {
.main {
.bigColumn {
width: 100%;
}
.adColumn {
display: none;
}
}
}
However this is not working. The ad never disappears and the rest of the content doesn't do anything in terms of filling the rest of the page when shrinking the window. If I change the background color in the .main the color changes, but changing anything in the two divs has no effect that I can see. I can get the social media icons to disappear at 760px just fine, so am I just missing something with the media query for the columns? Or could something else be interfering with it?
EDIT: Guess I should mention that yes, I am indeed using SASS in the project.
Here is the styling I have for the columns before I started the media query:
.main {
width: 90%;
display: flex;
min-height: 200px;
margin: 0 auto;
//column for main-page content
.bigColumn {
width: 800px;
height: 100%;
margin-top: 20px;
margin-right: 9%;
margin-left: 13%;
}
.adColumn {
margin-top: 20px;
position: relative;
min-height: 120px;
}
}
I don't believe you can nest your CSS like that unless you are using a preprocessor like LESS or SASS. Try taking the .bigColumn CSS out of the .main brackets and leave it on its own.
#media only screen and (max-width: 960px) {
.bigColumn {
width: 100%;
}
.adColumn {
display: none;
}
}
Based on your css I think you're close, but there appears to be a an error in the way you've structured your css. Give this a try. I'm assuming .bigColumn and .adColumn are children of .main:
/* All screens 960px or less */
#media only screen and (max-width: 960px) {
.main .bigColumn {
width: 100%;
}
.main .adColumn {
display: none;
}
}

Flex short hand property fallback

So I'm having an issue with flexbox in css. Particularly when using the flex shorthand property. For example:
If I have flex: 0 0 30%
In IE it just seems to get ignored in certain places. I'm using modernizr so I'm targeting the selector as:
.no-flex{
.st-col-thirds {
width: 33%;
}
}
Which I thought would work... But it doesn't.
Then I tried:
.no-flex{
.st-col-thirds {
min-width: 550px;
margin: 5px;
}
}
This works but it's super hacked and it's not responsive.
This is not a duplicate question.

CSS calc() behaviour in CSS variables

I'm curious to the behaviour of using calc() in setting a CSS variable.
Example:
#test {
--halfWidth: calc(100% / 2);
}
Now, if the #test element, say a div, was 500px wide, I would like the --halfWidth variable to be set to 250px.
But, as far as I can tell the var(--halfWidth) code used elsewhere simply drops in the calc(100% / 2) string instead of 250px. Which means that I can't use the calculation of say element A and use it in element B later on, since it would simply set for example width: var(--halfWidth); as half the width of element B instead of half the width of element A, where the variable was defined.
I've scoured the web trying to find any documentation on the behaviour of this, but I have so far drawn a blank.
Ideally, setting a CSS variable using calc should be available in two variants:
One variant working just like this example, simply dropping in the string as-is, bar any in-string variable replacements.
A second variant where calc() would yield the result of the calculation instead of simply replacing the string.
How to achieve this? I'd rather leave the actual implementation to people suited to it, but one possibility would be an eval() kind of thing; like eval(calc(100% / 2)) would give the result 250px.
Anyway, if anyone have any real documentation on this behaviour or a solution to how to get the example above to yield the result instead, I'm all ears!
Edit: Just FYI, I have read the specs at https://drafts.csswg.org/css-variables/
This is kind of a tough question to answer cause the answer will not be:
Do it like this...then it will work
The problem you are facing is the normal behavior of CSS. It cascades the styles. If what you are trying to achieve would work it would get real messy after a short amount of time.
I mean how cool is it that you can define a variable like this
#test {
--halfWidth: calc(100% / 2);
}
where var(--halfWidth) should always be calc(100% / 2). Did you note that it will always be half the width of the parent element?
Imagine how strange it would be if a programmer in a few months reads your code and has box with a width of 1000px set with --halfWidth and now it is 250px wide ... I would think the internet is broken :) It should just be 500px wide.
To achieve what you want, you could/should define different vars defining the widths of the parent elements. And split it down to the children.
One approach to this is to dynamically add a line to the CSS Object Model (CSSOM) which explicitly declares the width of the .halfwidth class.
This width will then apply to all divs with the .halfwidth class.
In the example below, I have, additionally, made .element-a horizontally resizable, so that you can see more clearly that as you change the width of .element-a, the width of both .halfwidth divs changes proportionately, including the .halfwidth div which is a child of .element-b.
Working Example:
let myStylesheet = document.styleSheets[0];
const elementA = document.getElementsByClassName('element-a')[0];
let elementAWidth = window.getComputedStyle(elementA).getPropertyValue('width');
const calculateHalfWidth = (elementAWidth) => {
myStylesheet.insertRule('.halfWidth { width: ' + (parseInt(elementAWidth) / 2) + 'px; }', myStylesheet.cssRules.length);
}
calculateHalfWidth(elementAWidth);
// ================================================================================
// THE SCRIPT BELOW USES A ResizeObserver TO WATCH THE RESIZABLE .element-a DIV
// ================================================================================
const elementAObserver = new ResizeObserver(entries => {
for (let entry of entries) {
if (entry.contentRect.width !== elementAWidth) {
calculateHalfWidth(entry.contentRect.width);
}
}
});
elementAObserver.observe(elementA);
body {
font-family: sans-serif;
}
div.element {
float: left;
width: 200px;
height: 100px;
margin: 12px 3px;
text-align: center;
border: 1px solid rgb(0, 0, 0);
}
div.element h2 {
font-size: 18px;
}
div.element-a {
resize: horizontal;
overflow: auto;
}
div.element-b {
width: 300px;
}
div.halfWidth {
height: 40px;
margin: 0 auto;
border: 1px dashed rgb(255, 0, 0);
}
div.halfWidth h2 {
font-size: 14px;
}
<div class="element element-a">
<h2>Element A</h2>
<div class="halfWidth">
<h2>halfWidth</h2>
</div>
</div>
<div class="element element-b">
<h2>Element B</h2>
<div class="halfWidth">
<h2>halfWidth</h2>
</div>
</div>

Chrome and Media Queries Bug

I'm trying to make a website that is essentially a few vertically positioned slides. I had been hoping to make a responsive design so my "slides" are appropriately resized on larger screen sizes or are padded appropriately in strange dimensions. Here is my LESS file setting the appropriate dimensions:
html, body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
//============================================================
// Dimensions for each section for standard desktop screen
//============================================================
#home {
#media screen and (min-aspect-ratio: 16/10) {
height: 92%;
width: 160vh;
padding: 0 calc(50% - 80vh);
}
#media screen and (max-aspect-ratio: 16/10) {
width: 100%;
height: 57.5vw;
}
}
#about {
#media screen and (min-aspect-ratio: 16/10) {
height: 108%;
width: 160vh;
padding: 0 calc(50% - 80vh)
}
#media screen and (max-aspect-ratio: 16/10) {
width: 100%;
height: 67.5vw;
}
}
#experience, #hobbies, #contact {
#media screen and (min-aspect-ratio: 16/10) {
height: 100%;
width: 160vh;
padding: 0 calc(50% - 80vh);
}
#media screen and (max-aspect-ratio: 16/10) {
width: 100%;
height: 62.5vw;
}
}
//============================================================
// colors
//============================================================
#home {
background-color: black;
}
#about {
background-color: #488BFF;
}
#experience {
background-color: #B3B3B3;
}
#hobbies {
background-color: #FF7F35;
}
#contact {
background-color: #803A7D;
}
It seems to work for the most part when I run it with a simple html file with the 5 divs (home, about, experience, hobbies, contact). However, on chrome, a bug seems to occur while I resize. Sometimes, my webpage simply disappears, replaced with some black/gray cross. If I resize very quickly (rapidly resizing the window), a checkerboard appears or even some other webpage completely on a different tab. I tried testing resizing another webpage also using media queries, and this problem did not happen. Is there something inherently wrong with how I'm using media queries?
EDIT: Sample images showing the strange problems:
After a long and arduous chat session, we have worked out a fix for the bug. Here is the summary:
What's Wrong
For some reason, Chrome has a problem rendering large divs. As of now, I'm not sure where the bug lies exactly, but a simple example with 5 100% width/height divs causes this strange problem. Here is a JSFiddle with this example. The bug only manifests outside of a frame, so you must copy the frame source into its own webpage.
From what I can gather, something strange is happening under the hood in Chrome's rendering engine on Windows, which causes the strange black & gray crosses to appear when resizing a window.
The Fix
The fix isn't very elegant, but it works. Simply apply a transform:rotate(0) on each of the divs to force gpu acceleration. With this, the cross vanishes. Here is the resulting JSFiddle that applies this fix on the previous example.
TL;DR
When Chrome isn't rendering the pages with the graphics card, strange things occur. Use transform:rotate(0) on broken items to force graphic card rendering.

SASS: Can I get element count in one class?

I want to position divs next to each other spaced equally and reposition them if the window size is changed. For that I think I need SASS. One time there may be 14 divs, other 10 divs in one class and I want them to be spaced equally depending on the count and the screen size. Can I get element count in SASS for one class?
Or you can do that with pure css and flex property
.equalSpaces {
overflow: hidden;
display: flex;
}
.equalSpaces p {
padding: 5px;
margin: 0;
background-color: #000;
border: 1px solid #999;
}
.equalSpaces div {
display: inline-block;
flex: 1; /* to make all blocks equal */
}
An example: http://jsfiddle.net/LbxyLmpg/
edit: #cimmannon suggestion display: inline-block;
You just need to use jQuery for this. Not AJAX or SASS. The reason is, AJAX is server side and SASS is just precompiled CSS, nothing more. So, you need to make it this way:
$(document).ready(function(){
$(".equalSpaces").each(function(){
totalDivs = $(this).find("div").length;
$(this).find("div").width(100/totalDivs + "%");
});
});
Fiddle: http://jsfiddle.net/praveenscience/h72horvz/

Resources