styling svgs that are inline of css - css

.player
{
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><line x1='1' y1='1' x2='9' y2='9' stroke='red'/><line x1='1' y1='9' x2='9' y2='1' stroke='red'/></svg>");
width: 100%;
height: 100%;
display: inline-block;
}
.one
{
fill: black;
}
.two
{
stroke: white;
}
Elements with the player class will have a background image that is an svg. If there are elements with both the player and the one or two class, is it possible to change the style of the svg if it's inlined like so? If not, how would I do a simple color change by having classes? Ideally, I wouldn't want to introduce any more markup in the html and prevent http accesses for such a small svg file.

As Douglas wrote, you can style only IMG elements with inline "src".
I use this technique:
Use common image with the path to your SVG:
<img src="my.svg" alt="">
Transform the "src" to inline style using JavaScript (jQuery):
$('img').each(function(){
var $img = jQuery(this);
var imgID = $img.attr('id');
var imgClass = $img.attr('class');
var imgURL = $img.attr('src');
jQuery.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = jQuery(data).find('svg');
// Add replaced image's ID to the new SVG
if(typeof imgID !== 'undefined') {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if(typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http://validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// Replace image with new SVG
$img.replaceWith($svg);
}, 'xml');
});
Style your SVG using CSS:
path {
fill: #f00;
}
Done.

In order to modify your SVG with CSS, you have to use inline SVG, you can't modify it with a class if you use it as a background-image to an element.
If you want to make your authoring look cleaned up you can use a server side script to push the SVG's markup to your page (such as PHP's file_get_contents()).
Since there's no way around this, just compress your SVG as much as possible (I like this tool, there's some other good ones on the source I attached) and then write your svg as cleanly as possible, it shouldn't be that bloated looking if it's a small file.
Source: https://css-tricks.com/using-svg/
Sorry I couldn't be the bearer of better news.

Related

Using SVG Icons

I'm using use my own SVG icons and I'm trying to find the best way of using them.
I would like to keep the color but also adjust it if needed to match a theme or on when using hover.
I have tried using the following script which changes the following into an embedded SVG but as I load my scripts at the bottom of my HTML doc, I get a horrible jumping effect.
$(function(){
jQuery('img.svg').each(function(){
var $img = jQuery(this);
var imgID = $img.attr('id');
var imgClass = $img.attr('class');
var imgURL = $img.attr('src');
jQuery.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = jQuery(data).find('svg');
// Add replaced image's ID to the new SVG
if(typeof imgID !== 'undefined') {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if(typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http://validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// Check if the viewport is set, else we gonna set it if we can.
if(!$svg.attr('viewBox') && $svg.attr('height') && $svg.attr('width')) {
$svg.attr('viewBox', '0 0 ' + $svg.attr('height') + ' ' + $svg.attr('width'))
}
// Replace image with new SVG
$img.replaceWith($svg);
}, 'xml');
});
});
svg {width: 350px; height: 350px;}
svg path {fill: #000 !important;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img src="https://upload.wikimedia.org/wikipedia/commons/f/f8/Windows_logo_-_2012_%28red%29.svg" alt="Microsoft" width="350" />
I've then tried to embed the the SVG by copying the code from Illustrator but the only way I can edit the colours is if I delete them in the html doc as my css won't override them.
What is the best way while keeping them from jumping?
Inline SVGs would be best IMO.
Export your SVGs using Illustrator (if you have troubles, follow this excellent guide by Colin Lord).
Then remove the colors from your SVG code and set them only using CSS.
If you have trouble overriding your colors you can give your SVGs IDs for more specifity.
If you go down the embedded route (which is my preferred option) - you don't actually need the majority of the HTML that Illustrator usually throws out.
Here is an example of your SVG with the most minimal code, then you can just use CSS to change the colours how you wish :-)
svg {
width: 350px;
height: 350px;
}
svg path {
fill: #000;
transform-origin: 0 0;
transform: scale(3)
}
#svg3 path {
fill: turquoise;
}
#svg3:hover path {
fill: green;
}
<svg id="svg2">
<path d="m0,12.402,35.687-4.8602,0.0156,34.423-35.67,0.20313zm35.67,33.529,0.0277,34.453-35.67-4.9041-0.002-29.78zm4.3261-39.025,47.318-6.906,0,41.527-47.318,0.37565zm47.329,39.349-0.0111,41.34-47.318-6.6784-0.0663-34.739z" id="path4"/>
</svg>
<!-- Another exmaple below using CSS to change the colours -->
<svg id="svg3">
<path d="m0,12.402,35.687-4.8602,0.0156,34.423-35.67,0.20313zm35.67,33.529,0.0277,34.453-35.67-4.9041-0.002-29.78zm4.3261-39.025,47.318-6.906,0,41.527-47.318,0.37565zm47.329,39.349-0.0111,41.34-47.318-6.6784-0.0663-34.739z" id="path4"/>
</svg>

SVG shadow-root is closed

I have tried to animate an svg-sprite with CSS.
I’ve created a sprite and injected it from gulp:
gulp.task('svgstore', function () {
var svgs = gulp
.src('app/svg/*.svg')
.pipe(svgmin(function (file) {
return {
plugins: [{
cleanupIDs: {
minify: true
}
}]
}
}))
.pipe(svgstore({ inlineSvg: true }));
function fileContents (filePath, file) {
return file.contents.toString();
}
return gulp
.src('app/*.html')
.pipe(inject(svgs, { transform: fileContents }))
.pipe(gulp.dest('app/'))
});
…and inserted images from the sprite to HTML:
<svg class="icon-ufo" >
<use xlink:href="img/sprite.svg#ufo" aria-hidden="true"></use>
</svg>
And it works well, but the following image shows the shadow DOM is closed.
How I can to animate some styles of this SVG without JavaScript? But if JavaScript is the only way, how to do it better?
The DOM of the referenced element is not part of the DOM of the referencing HTML page. It has isolated style sheets.
But the shadow element inherits styles from the referencing <use> element. This means that as long as the referenced element does not set the styles itself in the sprite or in a style sheet associated with the sprite, you can change (and animate) every inheritable style property on the icon by styling the <use> element.
You could use "currentColor" property in your fill attribute to styling:
and styles for "icon-ufo" class will be like
.icon-ufo {
color: green;
}
.icon-ufo:hover {
color: red;
}

Responsive Props in Vue Component

I have a prop called src in a Vue Component that binds to a :style like this:
<template>
<section :class="color" class="hero" :style="{ backgroundImage: src && 'url(' + src + ')' }">
<slot></slot>
</section>
</template>
<script>
export default {
props: ['src', 'color']
}
</script>
What I would like to do is to create a list of responsive props that get used depending on the device or screen size of the site visitor.
For instance, I imagine a list of props like src-sm, src-md, src-lg, etc. The user would enter different image urls for different device sizes and the style attr would use the appropriate url depending on the screen/size.
Is this possible in VueJS. If so, any idea how?
Thanks.
Unfortuently what you are trying to do is not trivial. This is because inline style tags can not accept media queries.
The spec declares:
The value of the style attribute must match the syntax of the contents of a CSS declaration block
Solution 1:
This solution is the simplest, perhaps not entirely what you are looking for.
It works by including img elements, and showing an hiding them via CSS.
<template>
<div>
<img class="image--sm" :src="src.sm" />
<img class="image--md" :src="src.md" />
<img class="image--lg" :src="src.lg" />
</div>
</template>
<script>
export default {
props: {
src: Object
}
}
</script>
<style>
.image--md,
.image--lg {
display: none;
}
#media (min-width: 400px) {
.image--sm {
display: none;
}
.image--md {
display: block;
}
}
#media (min-width: 600px) {
.image--md {
display: none;
}
.image--lg {
display: block;
}
}
</style>
Example: https://jsfiddle.net/h3c5og08/1/
Solution 2:
Image tags may not be the desired effect you are trying to achieve. This solution creates a style tag in the head and injecting the css content to change the background images.
You can not have style tags in Vue template. It will throw an error like:
Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as , as they will not be parsed.
As the error describes vue is designed the map state the UI. Using style tags in the template is prohibited because you can cause leaks to the outer world.
Although you can not declaratively styles in a template, we can use a bit of JS in the mounted hook of the component to add targetted and dynamic styles.
First we will need to constrain dynamic styles to this element. We can use the internal id of the created component this._uid, attaching to scope the css. (Note this is internal API so can be subject to change)
<template>
<div class="image" :data-style-scope="_uid">
</div>
</template>
The next part is to generate the style in a computed property, to later inject into a style block. You can expand on this computed property, to conditionaly assign properties ect. Note: keep the properties to the dynamic values only.
css () {
const selector = `.image[data-style-scope="${this._uid}"]`
const img = val => `${selector} { background-image: url("${val}"); }`
const sm = img(this.sm)
const md = img(this.md)
const lg = img(this.lg)
return `
${sm}
#media (min-width: 200px) { ${md} }
#media (min-width: 300px) { ${lg} }
`
}
This generated string from the css computed property is what we will now use when creating the style tag at mount. At mount we create a style node and append to the head. Assigning the nodes to the vm for references.
Using the references in the vm we can watch changes to the computed updating the style node.
Remember to clean up before destorying the component, removing the style node.
{
data () {
return {
// Reference data properties
style: null,
styleRef: null
}
},
mounted () {
// Create style node
let style = document.createElement('style')
style.type = "text/css"
style.appendChild(document.createTextNode(''))
// Assign references on vm
this.styleRef = style
this.style = style.childNodes[0]
// Assign css the the style node
this.style.textContent = this.css
// Append to the head
document.head.appendChild(style)
},
beforeDestroy () {
// Remove the style node from the head
this.style.parentElement.removeChild(this.style)
},
computed: {
css () {
// ...
}
},
watch: {
css (value) {
// On css value change update style content
this.style.textContent = this.css
}
}
}
Working Example: https://jsfiddle.net/bLkc51Lz/4/
You could also try the module described here: https://alligator.io/vuejs/vue-responsive-components/ which is called vue-responsive-components
It lets the component change its CSS depending on its own width (not on the entire browser's width)

Change foundation svg color on hover

Hello so I've seen a lot of codes regarding the hover color change on svg's but I can't get it to work. The thing is I am using foundation icons, and here is a sample code:
<img src="svgs/fi-mail.svg">
Any idea on changing the color on hover?
You have to convert the SVG into a native <svg> tag and then you need to apply DOM traversal and CSS to change it. I have a quick snippet, that I modified from elsewhere, and you can use it to change the properties.
You need to make the SVG to be an inline SVG. You can make use of
this script, by adding a class svg to the image:
/*
* Replace all SVG images with inline SVG
*/
jQuery('img.svg').each(function(){
var $img = jQuery(this);
var imgID = $img.attr('id');
var imgClass = $img.attr('class');
var imgURL = $img.attr('src');
jQuery.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = jQuery(data).find('svg');
// Add replaced image's ID to the new SVG
if(typeof imgID !== 'undefined') {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if(typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http://validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// Replace image with new SVG
$img.replaceWith($svg);
}, 'xml');
});
And then, now if you do:
.logo-img path {
fill: #000;
}
Or may be:
.logo-img path {
background-color: #000;
}
This works!
Reference: img src SVG changing the fill color
You cannot change the color of an SVG that is included via an IMG tag. You can only modify inline SVG through CSS.
But the Zurb Foundation Icons are normally included as web-font, where each icon is just a simple text character, which can be styled as any other text. The idea to include a single SVG icon via an IMG tag deviates from the Foundation documentation. Please refer to the „How to use“ section in the docs-article you linked above…

Auto-resize an image in CSS without replacing HTML width / height attributes?

I'm trying to make an image fit nicely on different screen sizes without breaking the layout. The following bit of CSS helps:
.viewer .main img {
max-width: 100%;
height: auto;
}
But the trouble is this image changes. I use a bit of Javascript to create a new img element each time the image changes, instead of reusing the existing one. (This seems a little more reliable for what I'm doing). The browser doesn't know the image's size until it is loaded, creating an obvious flicker in the interim. I deal with that by setting the image's width and height attributes in HTML. Without the above CSS rule, that works fine.
With that CSS, the flickering is still there. For some reason, when I create a new img element, the CSS seems to be causing the browser to ignore its width and height attributes, so. It ends up as ignorant of the aspect ratio as it was before.
Here's a jsfiddle to illustrate the situation:
http://jsfiddle.net/7sDtN/
One of the images in there is very very big (138 MB), so be careful if you're on a metered connection :)
What I would love is to get the image to scale according to those dimensions I set in HTML. Preferably in a nice way. A Javascript solution isn't the end of the world (I'm already using it, for course), but if there's an elegant CSS solution that would be very nice.
I ended up solving this in a roundabout way by wrapping the image in a dedicated container, along with some strange looking javascript to keep it in place as the image loads. The dimensions for that container are calculated as in Sven's answer, but ultimately it lets the browser take over. This way layout changes are kept fairly minimal and we end up only doing this crazy stuff for the bit of time between images.
Here's a big wad of code, for completedness:
function Viewer(container) {
var viewer = this;
container = $(container);
var pictureBox = $('.picture', container);
var img = $('<img>').appendTo(pictureBox);
var hide = function() {
/* [snip] */
}
var getPictureDisplayHeight = function(picture) {
var ratio = picture.data.h / picture.data.w;
var displayWidth = Math.min(pictureBox.width(), picture.data.w);
var displayHeight = Math.min(displayWidth * ratio, picture.data.h);
return displayHeight;
}
var stopLoadingTimeoutId = undefined;
var stopLoadingTimeout = function() {
container.removeClass('loading');
}
var showPicture = function(picture) {
var imgIsChanging = img.data('picture') != picture;
container.show();
/* This code expects to be cleaned up by stopLoadingTimeout or onImgLoaded, which will not fire if img src doesn't change */
if (imgIsChanging) {
container.addClass('loading');
window.clearTimeout(stopLoadingTimeoutId);
stopLoadingTimeoutId = window.setTimeout(stopLoadingTimeout, 3000);
}
pictureBox.css({
'min-height' : pictureBox.height()
});
var displayHeight = getPictureDisplayHeight(picture);
if (displayHeight > pictureBox.height()) {
/* Grow pictureBox if necessary */
pictureBox.stop(true, false);
pictureBox.animate({
'height' : displayHeight
}, 150);
}
/* I wish I could set width and height here, but it causes the current image to stretch */
img.attr({
'src' : picture.fullPath
}).data('picture', picture);
}
var onImgLoaded = function(event) {
/* The load event might not be fired, so nothing here should be essential */
var picture = img.data('picture');
container.removeClass('loading');
var displayHeight = getPictureDisplayHeight(picture);
pictureBox.stop(true, false);
pictureBox.animate({
'min-height' : 0,
'height' : displayHeight
}, 150, function() {
pictureBox.css('height', 'auto');
});
window.clearTimeout(stopLoadingTimeoutId);
}
var onImgClicked = function(event) {
selectNextPicture();
}
var onPictureSelectedCb = function(picture) {
if (picture) {
showPicture(picture);
} else {
hide();
}
}
var init = function() {
img.on('click', onImgClicked);
img.on('load', onImgLoaded);
}
init();
}
Relevant HTML:
<div class="viewer" style="display: none;">
<div class="picture"></div>
<div class="caption"><div class="caption-text"></div></div>
</div>
And CSS:
.viewer .picture img {
display: block;
margin: 0 auto;
max-width: 100%;
height: auto;
}
This way we leave space around the image that is either the size of the next image or the size of the current image, and never the smaller size that seems to happen before a new image is loaded (which kept happening for some reason). There are probably a million solutions to this, and mine doesn't feel especially straight-forward, so I'm certainly curious to see others :)
If I understand you right, you can achieve your goal by using the following code
HTML
<div id="Wrapper">
<img id="MyPic" src="http://www.davidstorey.tv/wp-content/uploads/2012/05/image.php_.jpeg" alt="" width="300" height="200" />
</div>
CSS
body{
width:100%;
}
#Wrapper{
width:98%;
border:1px solid red;
}
jQuery
$("document").ready(function(){
var ratio=$("#MyPic").width() / $("#MyPic").height();
$("#MyPic").css("width","100%");
$("#MyPic").css("height", $("#MyPic").width()/ratio+"px");
});
Here is the link to jsfiddle

Resources