I've looked at Blueprint, Less, and SCSS and none of them appear to do what I want. I find this difficult to believe because handling vendor prefixes is the most frustrating part of writing CSS, so it would appear to be to be the first problem anyone who writes a CSS framework ought to address.
I want to know, is there a framework (or rails gem) that I can use, that allows me to write border-radius:5px and then let's me assume that it will create a rule with all the proper vendor prefixes?
Thanks
You can actually do this quite easily with a LESS Mixin - basically you write it once and from there on out you apply it with one line. Like this:
// Border Radius
.border-radius(#radius: 5px) {
-webkit-border-radius: #radius;
-moz-border-radius: #radius;
border-radius: #radius;
}
Then you symply do this one-liner where you need a border radius:
.classname {
.border-radius(5px);
}
If you are not ready for LESS, then you could just process your code through Prefixr - it generates the browser prefixes for you (then you have to copy paste the code back into your file).
you can use that: http://sjevsejev.blogspot.com/2012/07/lessjs-function-generates-prefixes-for.html
then it would be enough to use:
.pf('transition','all 1s ease-in-out');
.pf('border-radius',3px);
.pf('box-shadow','2px 2px 5px 0 rgba(0,0,0,.6)');
.pf('flex', 1);
Perhaps a recently published collection of scss to css vendor prefix repository might be of interest, following is pulled from the border-radius.scss file...
#mixin border-radius($value) {
#include render-vendor-prefixes(
$property: border-radius,
$value: $value,
$vendor-list: (
-webkit, // Android 2.1, Chrome 5.0/4.0, iOS 3.2-, Safari 5.0/3.1,
-moz, // Firefox 4.0/3.0
),
$prefix: property,
);
}
Using the above #mixin could look like...
#import '_scss/modules/vendor-prefixes/lib/map-vendor-prefixes.scss';
#import '_scss/modules/vendor-prefixes/lib/render-vendor-prefixes.scss';
#import '_scss/modules/vendor-prefixes/calc.scss';
.something {
#include border-radius(10% 30% 50% 70%);
}
... and for completeness, the above complies to...
.something {
-webkit-border-radius: 10% 30% 50% 70%;
-moz-border-radius: 10% 30% 50% 70%;
border-radius: 10% 30% 50% 70%;
}
Related
I am trying to achieve an effect in which the border of an element would go through every color of the rainbow. I was able to find a solution which works very well on Chrome and on Edge, but doesn't work on Firefox due to the lack of support of the conic-gradient property.
Here is the working example I described:
.rainbow-border {
border: double 7px transparent;
background-image: linear-gradient(LightSteelBlue, LightSteelBlue), conic-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
background-origin: border-box;
background-clip: content-box, border-box;
}
body {
background-color: LightSlateGrey;
}
#keyframes border-radius-anim {
0% { border-radius: 0px; }
100% { border-radius: 90px; }
}
.main {
width: 80px;
height: 80px;
border-radius: 999px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0px 5px 25px rgba(0, 0, 0, 0.3);
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation: border-radius-anim 5s infinite alternate both;
}
<div class="main rainbow-border"></div>
I am working on a project in which different elements have this border, they can have different border width and I should animate it on hover. This solution works perfectly fine for my problem, however not in Firefox and support is required for this browser.
One easy working solution is to replace the conic-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000) by some url(url_to_conic_gradient_image), however I am wondering if a purely CSS solution exists, and if so what it looks like.
Using a JS library as a polyfill
As yunzen pointed out, it exists a polyfill for conic-gradient, it works really well from my tests, and it was able to cover this edge case.
Famous Lea Verou made a polyfill: leaverou.github.io/conic-gradient – yunzen
You will have to include 2 javascript files in your project for it to work. What it will do is look for all the conic-gradient css properties in your document and replace those with
a background-image generated based on the conic-gradient property values. So if your css property is loaded at the same time as the DOM, you can use this library and use conic-gradient as if it was supported by all the browsers.
However, if your css is generated after the DOM has loaded, you will have to use another approach which works by generating an image using the library, and then assign it instead of the conic-gradient css function:
var gradient = new ConicGradient({
stops: "gold 40%, #f06 0", // required
repeating: true, // Default: false
size: 400 // Default: Math.max(innerWidth, innerHeight)
});
console.log(gradient.svg); // SVG markup
console.log(gradient.png); // PNG image (fixed dimensions) as a data URL
console.log(gradient.dataURL); // data URL
console.log(gradient.blobURL); // blog URL
Pure css work-around (linear-gradient fallback)
If you are looking for a css-only approach (the main concern being that this library uses some computational power of the javascript thread to generate the images, which can become a big overheat depending on your use case), I will leave here a solution which proposes a pure-css fallback to the lack of support of conic-gradient, but you will lose the conic gradient effect, which may or may not be suited to your use case:
border: double 4px transparent;
background-image: linear-gradient(white, white), linear-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
background-image: linear-gradient(white, white), conic-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
background-origin: border-box;
background-clip: content-box, border-box;
The line with the conic-gradient will be ignored in the browser in which it isn't supported, leaving the linear gradient as a fallback. So you will lose the conic effect but have a decent visual fallback.
The advantages of the second solution is to free your Javascript thread from generating images to replace the conic-gradient, and as time goes you won't have to update your code if conic-gradient gets supported.
I've a strange problem with transforms in compass.
I want to move the axis with transform-origin(50% 100%) to the bottom, which is working if i type it into firebug.
But if I use the mixin #include transform-origin(50% 100%) it's not visible in firebug.
Only the rotation part is applied #include transform(perspective(600px) rotateX(45deg) rotateY(0deg) rotateZ(0deg));.
In compiled CSS I can find this line but it's not applied somehow and written with three values.
-moz-transform-origin:50% 100% 50%;
My SASS looks like this:
div#loader {
#include transition-property(transform);
#include transition-duration(3s);
#include transform(perspective(600px) rotateX(45deg) rotateY(0deg) rotateZ(0deg));
#include transform-origin(50% 100%); // This is not taking affect in final css
position: fixed;
bottom: 0;
left: 0;
background-color: #000;
width: 100%;
height: 100%;
margin: 0 auto;
}
What could be the reason for that?
If I write the line -moz-transform-origin:50% 100%;directly in my SASS it's working too.
Compass think, that you pass only one parametr(without comma) and try to add another. In the documentation of the compass you can find this comment:
// Transform-origin sent as individual arguments:
//
// #include transform-origin( [ origin-x, origin-y, origin-z, 3D-only ] )
so you should use the following code:
#include transform-origin(50%, 100%);
I have an image built from multiple css sprites, as described in this question: css image building with sprites
How would I use that so that I could apply a size on the top container that would dynamically re-size all the children?
here is the working fidlle so far: http://jsfiddle.net/hWhUb/3/
here is the current html structure:
<div class="icon">
<div class="brigade brigade-purple-left"> </div>
<div class="brigade brigade-purple-middle"> </div>
<div class="brigade brigade-purple-right"> </div>
<div class="icon-type icon-hero"> </div>
</div>
I have a few questions, that might lead to a solution:
Why are you using multiple images for something that can be easily achieved using a bit of css3 and a single image (the cross thingie)? A single image can more easily be resized, as a percentage of the container width, or even using css3 background-size property.
If you must use images for each thing, could you possibly consider never using sprites, ever? Its maintainability is pure annoyance, especially if someone has to take the project away from you later on.
Perhaps a combination of both?
If you choose the second option, I suggest using data uris.
Here's a short explaination:
http://css-tricks.com/data-uris/
It saves one more http request than sprites, easier to maintain, and the difference in overall size is rather insignificant in my honest opinion, and support is great - IE8+ and all sane browsers our there.
Setting up is easy enough, especially if you use the all-mighty sass interpreter, but there are some nifty utils out there (command-line, gui or even web-based) to transform your images into base64.
It can even support IE7 with a little effort!
Edit 3.11.12
You can also add http://css3pie.com/ to the options to check out - it lets you do the css3 tricks we so love and adore with internet explorer. It's a bit unpredictable to my taste, but for a small feat like this it can definitely do the trick.
Further, I commented on your browser-support needs below. IE7 is not what's going to stop you;)
You can use a combo of zoom for webkit/ie and -moz-transform:scale for Firefox
[class^="icon-"]{
display: inline-block;
background: url('../img/icons/icons.png') no-repeat;
width: 64px;
height: 51px;
overflow: hidden;
zoom:0.5;
-moz-transform:scale(0.5);
-moz-transform-origin: 0 0;
}
.icon-huge{
zoom:1;
-moz-transform:scale(1);
-moz-transform-origin: 0 0;
}
.icon-big{
zoom:0.60;
-moz-transform:scale(0.60);
-moz-transform-origin: 0 0;
}
.icon-small{
zoom:0.29;
-moz-transform:scale(0.29);
-moz-transform-origin: 0 0;
}
One of the ways to achieve it will be to use inline CSS and to dynamically generate attribute values in JavaScript or PHP/What you use.
Assuming you know the width of the top container and the position of the css sprites
Calculate the left middle and right
You can also opt to generate the CSS code in a separate file
http://aquagraphite.com/2011/11/dynamically-generate-static-css-files-using-php/
Using a bit of jQuery I can make the elements resize to whatever you want (resizeTo):
$(document).ready(function () {
$('#resize').click(function (e) {
e.preventDefault();
var resizeTo = 100,
resizeRatio = Number(resizeTo) / Number($(".icon").width());
$(".icon").css('width', resizeTo);
$(".child").each(function () {
var childWidth = Number($(this).width()),
childHeight = Number($(this).height()),
newChildWidth = childWidth * resizeRatio,
newChildHeight = childHeight * resizeRatio;
$(this).css({ 'width': newChildWidth, 'height': newChildHeight });
});
});
});
However, size doesn't resize the sprites to fit the new box sizes so seems like a pointless task.
Fiddler: http://jsfiddle.net/hWhUb/4/
Though what you want to do can be accomplished, I think your approach is wrong. It's way more complicated than it needs to be, but the idea is sound.
Looking at your sprite, the only thing that can't be changed with CSS is the actual icons (the artwork). The rounded corners and background colors -- that's a different story.
CSS
.icon-cross {
background:purple url('cross.jpg') no-repeat 40px 12px;
border-radius:5px;
border:1px solid gray
}
#media only screen and (max-width:768px) {
.icon-cross {
background-size: 800px 1200px;
background-position; ??px ??px
}
}
#media only screen and (max-width:400px) {
.icon-cross {
background-size: 500px 900px;
background-position; ??px ??px
}
}
HTML
<div class="icon-cross"></div>
You can use css3 2d transforms:
.icon {
transform: scale(2);
-ms-transform: scale(2); /* IE 9 */
-webkit-transform: scale(2); /* Safari and Chrome */
-o-transform: scale(2); /* Opera */
-moz-transform: scale(2); /* Firefox */
}
and change the transform origin with: transform-origin
I'm new to Sass and struggling with this. I can't get the color to render in both hex (for IE) and rgba. Every little piece is frustrating me because I haven't mastered the syntax yet, and Google results for Sass are still sparse.
Here's the mixin:
#mixin transparent($hex, $a){
/* for IEGR8 */
background: transparent;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$a}#{$hex},endColorstr=#{$a}#{$hex});
zoom: 1;
/* for modern browsers */
background-color: rgba(#{$hex},.#{$a});
}
Such that #include transparent(#FFF,.4) should produce the nice, browser compatible transparent code below:
background: transparent;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#40FFFFFF,endColorstr=#40FFFFFF);
zoom: 1;
background-color: rgba(100,100,100,.40);
I've been noobing on the following for a couple hours:
The # required for #RGB format.
The . required for rgba alpha.
Both need to be included for the call to rgba(), however the # can't be included for the IE #AARRGGBB or it will look like #AA#RRGGBB, and the . can't be included for IE or it rejects #.AARRGGBB.
Am I missing a much simpler way to do this? Can this be done with Sass string manipulation or any slightly clever color cast function in Sass which handles this for me already?
#mixin transparent($color, $alpha) {
$rgba: rgba($color, $alpha);
$ie-hex-str: ie-hex-str($rgba);
background-color: transparent;
background-color: $rgba;
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie-hex-str},endColorstr=#{$ie-hex-str});
zoom: 1;
}
NOTE: The ie-hex-str is only available in recent versions, not sure when it was introduced though
I think I encountered a similar problem when I wanted to pass a url to the mixin. Instead of sending only the url I had the send the whole url parameter as a parameter to the mixin. If you understand what I mean?
example:
#mixin bg($url)
background: #000 $url repeat-x
insted of:
#mixin bg($url)
background: #000 url($url) repeat-x
Also, this might not the suited for your application, but I usually work around that problem using opacity:
#mixin transparent_bg($hex, $a){
/* for IEGR8 */
filter:alpha(opacity=$a)
zoom: 1;
/* for modern browsers */
background-color: $hex;
opacity: ($a*10)
}
This probably is as bulletproof as you'll get without a proper shim.
To build on seutje's answer, this lets you use ms-filter transparency if you're doing background-color on IE, but if you if you know the colour of the element behind the element you want to make transparent, you can use Sass's "mix" function to mix the two colours and get fake transparency - for any kind of colour. That means borders and text and all that jive. It's still a manual fallback but it'll give you the exact colour you're trying to simulate with a solid hex.
SCSS:
#mixin alpha-color($foreground-color, $property: 'background-color', $background-context-color: #fff) {
#{$property}: mix(
fade-in($foreground-color, 1),
$background-context-color,
percentage(opacity($foreground-color))
); // Browsers without color opacity
#{$property}: $foreground-color; // Decent browsers
#if $property == 'background-color' {
.lt-ie9 & { // IE8 has background filters; use them instead
#{$property}: transparent;
$ie-hex: ie-hex-str($foreground-color);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie-hex},endColorstr=#{$ie-hex});
zoom: 1;
}
}
}
To get border-color: rgba(255, 0, 0, 0.5) on a blue background, you'd use it like:
.blue-container {
$color-bg: rgb(0,0,255);
background-color: $color-bg;
.transparent-red-element {
#include alpha-color(rgba(255, 0, 0, .65), border-color, $color-bg);
}
}
Sass automatically turns 100% opacity colors back into a hex code, hence the fade-in of 100%.
The only browsers without colour opacity are IE8 <=8 and Opera <=9.6, and IE 8 has filters so this only helps for colors other than background-color. The principle is that you mix the background and foreground colours together into a flat hex.
ie-hex-str is like a year old now so you'll definitely have it.
In my CSS I have the following:
.Thing {
filter: alpha(opacity=40);
opacity:0.4;
-moz-opacity:0.4;
}
.Thing button {
filter: alpha(opacity=100);
opacity:1;
-moz-opacity:1.0;
}
However, the button is still .4 opacity. I then try opacity: 2 and such and it looks like I can give it less opacity but not more. Is there a way I can remove it or do I have to write multiple rules to get everything but the button?
I am testing with Firefox and Chrome.
use rgba with a rgb fallback.
background-color: rgb(0,0,0);
background-color: rgba(0,0,0, 0.5); /*ie6 will ignore this*/
rgba will only apply opacity to the target element.
What i've recently been doing is using the rgbapng sass/compass plugin which generates a png image to use as a fallback for browsers without rgba support.
Note: you'll still need to use an ie6 png fix for this to work.
Not a fix for the opacity issue but a possible workaround.
How about removing the button from the normal document flow and then placing back inside the .Thing
Something like this: http://jsfiddle.net/CqgkM/