Getting element width with compass - compass-sass

Is there any way to get a predefined element with with compass(CSS Framework)?
Let's say i have:
<ul>
<li class="class-1">foo</li>
<li class="class-2">foo</li>
<li class="class-3">foo</li>
</ul>
What i want outputted is:
ul > li {
position: absolute;
top: 0; left: 50%;
}
ul > li.class-1 { width: 20px; margin-left: -10px; }
ul > li.class-2 { width: 26px; margin-left: -8px; }
ul > li.class-3 { width: 24px; margin-left: -12px; }
If at all possible, I imagine I would have to do something like:
ul > li {
position: absolute;
top: 0; left: 50%;
&.class-1 { width: 20px; }
&.class-2 { width: 16px; }
&.class-3 { width: 24px; }
#for $i from 1 through 3 {
.class-#{$i} { margin-left: $item-width / 2; }
}
}
But $item-width naturally isn't defined. Is there any way to calculate it in the case described above?

I don't think it is possible to reference a predefined element, as there are no predefined elements... In other words all elements are defined by you.
So the easiest way around this is create a mixin with includes as follows
#mixin counter($num) {
width: $num+px; margin-left: - $num/2+px;
}
ul < li {
position: absolute;
top: 0; left: 50%;
&.class-1 { #include counter(20); }
&.class-2 { #include counter(16); }
&.class-3 { #include counter(24); }
}
Hope this still helps someone as I notice it is quite old.

Related

Using media queries, following standards with SASS and BEM?

I am following the BEM practice and want to add specific break points, it appears 2 formats work for me. Does anyone know the advantage of either ?
Here is the first, I embed the media directly into the element (BEM)
.my-component {
&__section-field {
display: flex;
flex-wrap: wrap;
}
&__section-sep {
width: 100%;
#media(min-width: 900px) {
width: 50%;
}
}
}
Here is the second, where I embed the media query outside of the section and redefine the section again.
.my-component {
&__section-field {
display: flex;
flex-wrap: wrap;
}
&__section-sep {
width: 100%;
}
#media(min-width: 900px) {
&__section-sep {
width: 50%;
}
}
}
As you can see the, I am basically changing the width of an item between either 50% or 100% depending if it's mobile only resolution. I am using flexbox with flex-wrap and it wraps depending on there is space left on the line.
They both seem to work the same as far as I can say. Would anyone confirm if there is a difference and which one would be more scalable and maintainable?
Maybe there is something that I haven't thought of, I did think about storing my media queries in a separate file but I was trying to keep everything together and follow the bem methodology.
I prefer the 2nd variant for the following reason: when you have many media queries, indeed, the 1st variant requires less copy/paste.
But though, the code becomes much less readable if you have many elements or modifiers in the block, i.e. selectors. It's common to face a situation when it's needed to change style for several elements/modifiers at exact screen. And when that case appears - as for me - it's easier to navigate between media queries, find the needed media and change code there - so you work at one place in the file, whereas in the 1st variant you would need to jump between selectors. In my opinion when it comes to work with media queries - it's faster to navigate between them, then to navigate between selectors.
imagine the following code with media query inside every selector :
.section_name_educational {
display: flex;
flex-direction: row;
padding: 0px;
.fp-tableCell {
display: flex;
flex-direction: row;
}
.section {
&__inner {
display: flex;
flex-direction: row-reverse;
height: 100vh;
height: calc(100vh - 80px);
box-sizing: border-box;
width: 50%;
padding-left: 40px;
margin-top: auto;
padding-bottom: 40px;
}
&__header {
position: relative;
width: 100%;
top: 62px;
left: 40px;
}
&__text-holder {
width: 100%;
}
&__title {
font-size: 48px;
}
&__subtitle {
width: 150%;
margin: 20px 0px;
}
&__description {
color: #669900;
font-size: 18px;
}
&__primary {
height: 100%;
display: flex;
box-sizing: border-box;
flex-direction: column;
justify-content: space-between;
width: 100%;
}
&__additional {
display: none;
}
&__kettles {
display: flex;
}
&__kettle {
height: auto;
margin-right: 20px;
&_order {
&_1 {
width: 183px;
min-width: 183px;
max-width: 183px;
}
&_2 {
width: 108px;
min-width: 108px;
max-width: 108px;
}
&_3 {
width: 127px;
min-width: 127px;
max-width: 127px;
}
}
}
&__background-holder {
overflow: hidden;
max-height: 100vh;
}
&__background {
position: relative;
width: auto;
height: 100vh;
}
}
}
#media all and (max-height: 600px) {
.section_name_educational {
.section {
&__kettle {
&_order {
&_2 {
width: 68px;
max-width: 68px;
min-width: 68px;
height: 120px;
margin-left: 30px;
}
&_3 {
width: 78px;
max-width: 78px;
min-width: 78px;
height: 120px;
}
}
}
}
}
}
#media all and (max-height: 760px) {
.section_name_educational {
.section {
&__header {
top: 40px;
}
&__subtitle {
width: 100% !important;
}
&__additional {
display: none !important;
}
}
}
}
#media (--large) {
.section_name_educational {
.section {
&__subtitle {
width: 120%;
}
}
}
}
#media (--xlarge) {
.section_name_educational {
padding-top: 120px;
.section {
&__inner {
height: calc(100vh - 60px);
margin-top: 0;
}
&__header {
transition-delay: 1s;
opacity: 0;
right: -100px;
bottom: -40px;
transform: translateY(20px);
}
&__subtitle {
width: 120%;
}
&__primary {
width: calc(100% - 160px);
}
&__additional {
display: flex;
flex-direction: column;
justify-content: space-between;
}
&__bubbles {
display: block;
position: relative;
top: 40px;
width: 160px;
min-width: 160px;
max-width: 160px;
height: auto;
transform: translateY(20px);
opacity: 0;
transition-delay: 1s;
}
&__kettle {
opacity: 0;
transform: translateY(20px);
transition-delay: 1s;
}
}
&.active {
.section {
&__header {
transition: opacity 1s ease-out 0.8s,
transform 0.8s ease-out 0.8s;
opacity: 1;
transform: translateY(0px);
}
&__kettle {
opacity: 1;
transform: translateY(0px);
transition: opacity 0.6s ease-out,
transform 0.6s ease-out;
&_order {
&_1 {
transition-delay: 1.6s;
display: block;
}
&_2 {
transition-delay: 1.9s;
}
&_3 {
transition-delay: 2.1s;
}
}
}
&__bubbles {
transition: opacity 0.8s ease-out 2.5s,
transform 0.8s ease-out 2.3s;
transform: translateY(0px);
opacity: 1;
}
}
}
}
}
#media all and (min-width: 1400px) {
.section_name_educational {
.section {
&__header {
left: 60px;
}
&__subtitle {
width: 110%;
}
}
}
}
#media (--xxlarge) {
.section_name_educational {
.section {
&__primary {
width: calc(100% - 148px);
}
&__subtitle {
width: 80%;
margin: 40px 0px;
}
&__description-inner {
width: 60%;
}
&__bubbles {
width: 148px;
min-width: 148px;
max-width: 148px;
top: 40px;
}
}
}
}
#media (--monster) {
.section_name_educational {
.section {
&__primary {
width: calc(100% - 227px);
}
&__header {
left: 200px;
top: 150px;
}
&__title {
font-size: 58px;
}
&__subtitle {
font-size: 24px;
width: 80%;
}
&__description {
font-size: 24px;
}
&__bubbles {
width: 227px;
min-width: 227px;
max-width: 227px;
left: 0px;
}
}
}
}
As for me - it would be difficult to read it if I had done it with the 1st variant.

Issue mixing variable with mixin with keyframe animation?

First time using SCSS, and testing my knowledge from the Sass-Lang.com guide. According to the guide, it is possible to both set variables and use mixins to simplify your CSS.
I was coding an animation where the div is clipped from bottom to top. I used variables to set the initial and final clip-path settings, and used them while calling a mixin. Yet I get the error, 'Invalid CSS after "...slider-initial)": expected "{", was "; }"'. What am I doing wrong?
Here is my code:
<body>
<section id='main'>
<div id='left'></div>
<div id='right'></div>
<section>
</body>
$slider-initial: inset(0 0 0 0);
$slider-final: inset(0 0 100% 0);
#mixin slider-clip($slider-state) {
-webkit-clip-path: $slider-state;
clip-path: $slider-state;
}
body {
height: 100%; width: 100%;
margin: 0 auto;
}
#main {
height: 64vh; width: 38vw;
margin: 0 auto;
margin-top: 10%;
position: relative;
display: flex;
flex-direction: row;
justify-content: center;
border: 1vh solid black;
}
#left {
order: 1;
width: 4%;
height: 100%;
margin-left: 46%;
background: green;
}
#right {
opacity: 1;
order: 2;
width: 4%;
height: 100%;
margin: auto;
margin-left: 0;
animation-name: dropdown;
animation-duration: 4s;
background: red;
}
#keyframes dropdown {
from { #mixin slider-clip($slider-initial); }
to { #mixin slider-clip($slider-final); }
}
You called your mixin in a wrong way:
#keyframes dropdown {
from { #mixin slider-clip($slider-initial); }
to { #mixin slider-clip($slider-final); }
}
In the guide on sass-lang.com, you can see the following example of how to include a mixin:
.box { #include border-radius(10px); }
Applied to your case, your code should look like this:
#keyframes dropdown {
from { #include slider-clip($slider-inital); }
to { #include slider-clip($slider-final); }
}

percentage padding inside ul li a "jumps" the LI

i'm creating this base structure :
<ul>
<li>
<a>
blabla
</a>
</li>
</ul>
with css :
ul{
height: 100%;
list-style: none outside none;
margin: 0;
padding: 0;
}
ul li{
height: 25%;
text-align: right;
width: 100%;
}
a{
display: block;
float: right;
height: 75%;
padding-right: 2%;
position: relative;
width: 98%;
padding-top:25%;
}
i can't manage to simply put the a at the bottom...
i thought giving the A a height of 25% and a padding of 75% would work but it takes 75% of the UL and not 75% of the LI.
anyone has an idea how come?
thanks a lot
What exactly are you trying to achieve?
If I am assuming correctly you want an <li> that is 25% the height of its container and the <a> to sit at the bottom-right of the <li>
If that is the case you could use this css
updated RE comment In this case we could use a <span> inside the <a> to position the text and set the <a> to fill the <li>
ul {
height: 100%;
list-style: none outside none;
margin: 0;
padding: 0;
background-color: red;
}
li {
height: 25%;
text-align: right;
width: 100%;
}
a {
display: block;
position: relative;
height: 100%;
width: 100%;
background-color: blue;
}
span {
display: block;
position: absolute;
bottom: 0;
padding: 2%;
width: 96%;
background-color: green;
}
and the html
<ul>
<li><span>blabla</span></li>
</ul>
Fiddle here
Please note that for this to work you need to set html, body { height:100%; } or have a container with an explicit height set. i.e. ul { height: 200px; } or div.container { height: 200px; }
I would also recommend applying the styles via classes.

Horizontal list with Susy grid

I want to build an android like main navigation that fits into a Susy Grid. It looks like this:
The code goes here:
HTML:
<div class="container">
<nav>
<ul class="horizontal-list">
<li>
One
</li>
<li>
Two
</li>
<li>
Three
</li>
<li>
Four
</li>
</ul>
</nav>
</div>
SASS:
header.main {
height: $headerHeight;
background: url('images/headerBackground.gif');
.container {
#include container;
#include susy-grid-background;
nav {
#include span-columns(8);
ul.horizontal-list {
#include horizontal-list;
overflow: visible;
li {
#include isolate-grid(2, 8);
padding: 0;
display: table;
a {
// vertical alignment
display: table-cell;
height: $headerHeight / 2;
padding-bottom: 2px;
vertical-align: bottom;
// appearance
color: $greyLight;
font-size: 18px;
text: {
transform: uppercase;
decoration: none;
}
// hover
position: relative;
&:before {
content: '';
display: block;
width: $headerUnderlineGap;
background: $black;
height: $headerHeight;
position: absolute;
top: 0;
margin-left: -$headerUnderlineGap + 1;
}
&:hover {
color: $white;
&:after {
content: '';
display: block;
background: $cyanLight;
width: 114%; // TODO check why space(2, 8) does not work
height: 4px;
position: absolute;
margin: -1px 0 0 1px;
}
}
}
}
}
}
}
}
I feel it's a bit hacky to set the width of the &:after element to 114% and not to space(2, 8). Can anyone tell me, how to set up a horizontal navigation with a Susy grid and an continuous underline, that hovers all the way to the next li element.
Thanks in advance!
space(2,8) doesn't work in that case because 8 is not actually the context: 2 is. You just need space(2,2).

Mixins and placeholder selector scope - Styles not being applied to current selector

I'm writing a mixin for adding a graphical effect to the corner of a box:
The mixin will accept a corner position (tl, tr, bl, br), size, and colors:
#mixin notch($notch-location, $size, $foreground-color, $background-color) {
%top--left {
#extend %notch;
&:before {
top: 0; left: 0;
border-width: $size $size 0 0;
}
}
// etc ...
%notch {
position: relative;
&:before {
#extend .pel;
position: absolute;
border-style: solid;
border-color: $foreground-color $background-color;
}
}
#if $notch-location == top-left {
#extend %top--left;
}
// etc ...
}
I then use the mixin on a selector, for example:
a {
#include notch(top-left, 24px, $color-brand, #fff);
}
Unfortunately the resulting CSS isn't what I'm expecting:
.menu.collapsed .nav .nav--current a a:before {
top: 0;
left: 0;
border-width: 24px 24px 0 0;
}
.menu.collapsed .nav .nav--current a a {
position: relative;
}
.menu.collapsed .nav .nav--current a a:before {
position: absolute;
border-style: solid;
border-color: #ec5b25 white;
}
Example:
SCSS (jsFiddle)
Compiled CSS (jsFiddle)
As you can see, the styles added via the mixin are being qualified with an extra a. Why is this happening?
The output is exactly as I would expect because of the nature of extends. The %notch class belongs to the parent selector (a in your case). If you change it to .notch instead, it becomes obvious.
Extend classes are not ephemeral. It's a good idea to avoid defining them within a mixin you plan on reusing. Doing so will cause the class to be generated each time you invoke the mixin, causing duplication of code all over the place (which you probably don't want).
%notch {
position: relative;
&:before {
#extend .pel;
position: absolute;
border-style: solid;
}
}
#mixin notch($notch-location, $size, $foreground-color, $background-color) {
#extend %notch;
border-color: $foreground-color $background-color;
&:before {
#if $notch-location == top-left {
top: 0; left: 0;
border-width: $size $size 0 0;
} #else if $notch-location == top-right {
top: 0; right: 0;
border-width: $size 0 0 $size;
} #else if $notch-location == bottom-left {
bottom: 0; left: 0;
border-width: 0 $size $size 0;
} #else {
bottom: 0; right: 0;
border-width: 0 0 $size $size;
}
}
}
a {
display: block;
width: 100px; height: 100px;
background: #0f0;
#include notch(top-left, 24px, #0f0, #0f0);
}
It's also worth noting that extends aren't always the best choice, they can cause the code to be larger than it would be if you'd simply duplicated the code due to repeating the selector.
You seem to have messed up your code structure.
I'm not sure why this extra a appears, but when i refactor your code to have reasonable structure, the problem disappears:
$color-brand: pink;
%notch {
position: relative;
&:before {
#extend .pel !optional;
position: absolute;
border-style: solid;
}
}
%top--left {
#extend %notch;
&:before {
top: 0; left: 0;
}
}
#mixin notch($notch-location, $size, $foreground-color, $background-color) {
border-color: $foreground-color $background-color;
#if $notch-location == top-left {
#extend %top--left;
border-width: $size $size 0 0;
}
// etc ...
}
a {
#include notch(top-left, 24px, $color-brand, #fff);
}
Demo: http://sassbin.com/gist/6019481/

Resources