I have a bunch of logo's, generated with illustrator, that I would like to embed in my website directly. The svgs all have a <style> element where the styles are defined inside the svg element, something like this:
<svg>
<style>
.st1 { fill:#ff00ff; }
.st2 { fill:#ff3421; }
/* ... and so on */
</style>
<!-- svg paths and shapes -->
</svg>
The problem is that these styles interfer with each other. So if the last images defines .st21 {fill:#555555} this style is applied to all path with class="st21", including paths from all previously loaded svg images.
In another thread somebody suggested to wrap my svg-xml with an <object> tag, that doesn't seem to work.
How can I make sure that inline SVG styles are not interfering with each other, without touching the actual SVG code?
here's a pen to illustrate the problem: https://codepen.io/pwkip/pen/RLPgpW
I would suggest to export svg with appropriate CSS properties in the first place.
During export from Illustrator choose :style attributes it would be something like this in svg:
<path style="fill: red"></path>
It could increase your file size but it definitely do the job. I found a nice explanation here
I came up with a JavaScript solution. Although this might be a little overkill and slow if you use a lot of SVGs. But this works fine so far.
What I do is, I iterate over all SVGs and collect/parse their CSS styles. I collect all class names and properties and apply them manually onto the SVG elements.
const svgCollection = document.querySelectorAll( 'svg' );
function parseStyles( styleTag ) {
if ( !styleTag ) {
return {};
}
const classCollection = {};
const plain = styleTag.innerHTML;
const regex = /\.([^\s{]+)[\s]*\{([\s\S]+?)\}/;
const propertyRegex = /([\w\-]+)[\s]*:[\s]*([^;]+)/;
const result = plain.match( new RegExp( regex, 'g' ) );
if ( result ) {
result.forEach( c => {
const classResult = c.match( regex );
const propertiesResult = classResult[ 2 ].match( new RegExp( propertyRegex, 'g' ) );
const properties = propertiesResult.reduce( ( collection, item ) => {
const p = item.match( propertyRegex );
collection[ p[ 1 ] ] = p[ 2 ];
return collection;
}, {} );
classCollection[ classResult[ 1 ] ] = properties;
} );
return classCollection;
}
return {};
}
function applyProperties( element, properties ) {
if ( !properties ) {
return;
}
Object.keys( properties ).forEach( key => {
element.style[ key ] = properties[ key ];
} );
}
function applyStyles( element, styles ) {
const classNames = ( element.getAttribute( 'class' ) || '' ).split( ' ' );
classNames.forEach( c => {
applyProperties( element, styles[ c ] );
} );
element.setAttribute( 'class', '' );
}
for ( let i = 0; i < svgCollection.length; i += 1 ) {
const svg = svgCollection[ i ];
const styles = parseStyles( svg.querySelector( 'style' ) );
const elements = svg.querySelectorAll( '[class]' );
for ( let j = 0; j < elements.length; j += 1 ) {
applyStyles( elements[ j ], styles );
}
}
<p>this shape should be blue:</p>
<svg height="210" width="210">
<style>
.st1 {
fill:blue;
}
</style>
<polygon points="100,10 40,198 190,78 10,78 160,198" class="st1"/>
</svg>
<p>this shape should be red:</p>
<svg height="210" width="210">
<style>
.st1 {
fill:red;
}
</style>
<ellipse cx="105" cy="80" rx="100" ry="50" class="st1" />
</svg>
Even though this works great, I wouldn't suggest it (as mentioned in the comments at your question). Better to set CSS Properties to Presentation Attributes in Illustrater
Related
I would like to add a 33% to the Wordpress Block "Button". So far it has 25%,50%,75% and 100%. Is it possible to insert my new value into the existing width selector?
I'm guessing Block Filters are the way to go.
I think I also found the way to get the settings object which might then help me to find out what I need to overwrite. However simply adding this code to my admin.js does not produce any output. Where would I need to load this?
const filterBlocks = (settings) => {
if (settings.name !== 'core/buttons') {
return settings
}
console.log(settings);
return settings;
}
Quick solution: Add a custom CSS class in the Buttons' block properties under "Advanced > Additional CSS class(es)" then define the custom width in your theme style.css
Detailed solution:
By using wp.hooks.addFilter() you can add a new control to the Button block with as many extra custom width options as you need. The Button blocks preset widths are defined within the function WidthPanel() of the blocks edit.js function:
function WidthPanel( { selectedWidth, setAttributes } ) {
...
return (
...
<ButtonGroup aria-label={ __( 'Button width' ) }>
{ [ 25, 50, 75, 100 ].map( ( widthValue ) => {
...
}
}
To add a new width value of 33% to the block, we need to add our own new button control to the InspectorControls and then use wp.hooks.addFilter() to add this to the existing core Button block, eg:
index.js
import { createHigherOrderComponent } from '#wordpress/compose';
import { Fragment } from '#wordpress/element';
import { InspectorControls } from '#wordpress/block-editor';
import { PanelBody, Button } from '#wordpress/components';
const withInspectorControls = createHigherOrderComponent((BlockEdit) => {
return (props) => {
const { setAttributes } = props;
let widthValue = 33; // must be a number
return (
<Fragment>
<BlockEdit {...props} />
<InspectorControls>
<PanelBody title="Custom Width">
<Button
key={widthValue}
isSmall
variant={widthValue}
onClick={() => setAttributes({ width: widthValue })}
>
{widthValue}%
</Button>
</PanelBody>
</InspectorControls>
</Fragment>
);
};
}, 'withInspectorControl');
wp.hooks.addFilter(
'editor.BlockEdit',
'core/button',
withInspectorControls
);
Next, a new additional css style needs to be added that (matches the existing width presets structure) for the new custom width, eg:
style.scss
$blocks-block__margin: 0.5em;
&.wp-block-button__width-33 {
width: calc(33.33% - #{ $blocks-block__margin });
}
And there you have it..
The easiest way to put all the code above together/working is to create your own Gutenberg block (and that in itself can be challenging if you aren't familiar with the process or ReactJS). I too have come across similiar challenges with Gutenberg, so I wanted to provide a detailed solution for this kind of issue that works.
I am using Vue for my project. A lot of my images are done using background-image.
<div :style="`background:url('${user.image});`"></div>
According to google if I am using an I can setup:
<picture>
<source srcset="img/awesomeWebPImage.webp" type="image/webp">
<source srcset="img/creakyOldJPEG.jpg" type="image/jpeg">
<img src="img/creakyOldJPEG.jpg" alt="Alt Text!">
</picture>
Is there a way to do something similar for background-image?
There is no truly CSS only solution, you'd have to rely on javascript for this.
The best is probably to have a 1x1px webp image and try to load it to then set a flag.
Unfortunately (?) this process is asynchronous.
function testWebPSupport() {
return new Promise( (resolve) => {
const webp = "data:image/webp;base64,UklGRkAAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAIAAAAAAFZQOCAYAAAAMAEAnQEqAQABAAFAJiWkAANwAP79NmgA";
const test_img = new Image();
test_img.src = webp;
test_img.onerror = e => resolve( false );
test_img.onload = e => resolve( true );
} );
}
(async ()=> {
const supports_webp = await testWebPSupport();
console.log( "this browser supports webp images:", supports_webp );
// for stylesheets
if( !supports_webp ) {
document.body.classList.add( 'no-webp' );
}
// for inline ones, just check the value of supports_webp
const extension = supports_webp ? 'webp' : 'jpg';
// elem.style.backgroundImage = `url(file_url.${ extension })`;
})();
.bg-me {
width: 100vw;
height: 100vh;
background-image: url(https://upload.wikimedia.org/wikipedia/commons/9/98/Great_Lakes_from_space_during_early_spring.webp);
background-size: cover;
}
.no-webp .bg-me {
/* fallback to png */
background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/9/98/Great_Lakes_from_space_during_early_spring.webp/800px-Great_Lakes_from_space_during_early_spring.webp.png);
}
<div class="bg-me"></div>
I'd like to set overflow-y: hidden for the html selector (not an element) based on whether a React class component state variable is true. Is that possible?
If you mean you want to apply the overflow-y to the actual HTML tag then putting this code in the render worked for me
...
render() {
let html = document.querySelector('html');
this.state.test === "test" ? html.style.overflowY = "hidden" : html.style.overflowY = "visible";
return (
....
)
};
You can do
function MyComponent() {
// Set your state somehow
const [something, setSomething] = useState(initialState)
// Use it in your className`
return <div className={!!something && 'class-name'} />
}
If you have multiple class names to work with, a popular package is (aptly named) classnames. You might use it like so:
import cx from 'classnames'
function MyComponent() {
const [something, setSomething] = useState(initialState)
return <div className={cx({
'some-class' : something // if this is truthy, 'some-class' gets applie
})} />
}
Yes, It's possible. You can do this.
function App() {
const [visible, setVisible] = useState(false);
useEffect(() => {
const htmlSelector = document.querySelector("html");
htmlSelector.style.overflowY = visible ? "unset" : "hidden";
}, [visible]);
return (
<button onClick={() => setVisible(prevState => !prevState)}>
Toggle overflow
</button>
);
}
See the full example on CodeSandbox
You can use the style property to set inline CSS:
<div style={{ overflowY: hide ? 'hidden' : 'auto' }}>
I have done a lot of looking but there is suprisingly little documentation in regard to reactstrap carousel image responsiveness.
My ReactStrap carousel resizes responsively but the images do not.
Options I have researched/tried:
CSS via className in the carousel component itself? This is the one I thought might be best, but I haven't found a combination of background-size, height, and max-width that resizes the image properly.
srcset ? I'm not sure how to implement this or any other inline attribute, given that the carousel is a component
Perhaps some place in the carousel component itself?
Or is there a better way for me to modify the images?
Or is #media the answer via css?
`
const items = [
{
src: 'img1.png',
altText: '',
caption: ''
},
{
src: 'img2.png',
altText: '',
caption: 'Freedom Isn\'t Free'
},
{
src: 'img3.png',
altText: '',
caption: ''
}
];
class HomeCarousel extends Component {
constructor(props) {
super(props);
this.state = { activeIndex: 0 };
this.next = this.next.bind(this);
this.previous = this.previous.bind(this);
this.goToIndex = this.goToIndex.bind(this);
this.onExiting = this.onExiting.bind(this);
this.onExited = this.onExited.bind(this);
}
onExiting() {
this.animating = true;
}
onExited() {
this.animating = false;
}
next() {
if (this.animating) return;
const nextIndex = this.state.activeIndex === items.length - 1 ? 0 : this.state.activeIndex + 1;
this.setState({ activeIndex: nextIndex });
}
previous() {
if (this.animating) return;
const nextIndex = this.state.activeIndex === 0 ? items.length - 1 : this.state.activeIndex - 1;
this.setState({ activeIndex: nextIndex });
}
goToIndex(newIndex) {
if (this.animating) return;
this.setState({ activeIndex: newIndex });
}
render() {
const { activeIndex } = this.state;
const slides = items.map((item) => {
return (
<CarouselItem
className="carouselImg"
onExiting={this.onExiting}
onExited={this.onExited}
key={item.src}
>
<img src={item.src} alt={item.altText} />
<CarouselCaption captionText={item.caption} captionHeader={item.caption} />
</CarouselItem>
);
});
return (
<Carousel
activeIndex={activeIndex}
next={this.next}
previous={this.previous}
>
<CarouselIndicators items={items} activeIndex={activeIndex} onClickHandler={this.goToIndex} />
{slides}
<CarouselControl direction="prev" directionText="Previous" onClickHandler={this.previous} />
<CarouselControl direction="next" directionText="Next" onClickHandler={this.next} />
</Carousel>
);
}
}
export default HomeCarousel;
`
Good day and Hello,
I already tried this reactstrap with the Carousel component in my reactjs app.
I solved this by adding bootstrap 4 classess "d-block w-100".
I created this in my reactstrap Carousel component and in this element
from this:
<img src={item.src} alt={item.altText} />
I changed to:
<img className="d-block w-100" src={item.src} alt={item.altText} />
I just copied these classes (d-block w-100) from bootstrap 4 documentation
https://getbootstrap.com/docs/4.0/components/carousel/
This is my example that I used Reactstrap Carousel with Dynamic data from my WordPress Rest API data.
https://github.com/jun20/React-JS-and-WP-Rest-API/tree/home-carousel-final
.carousel-item > img {
width: 100%;
}
... will fix your problem.
And it has nothing to do with Reactstrap. That's probably why you didn't find much. Has to do with the TwBs Carousel alone. I personally don't see any reason why that rule is not part of TwBs carousel CSS, because everyone expects that <img> to have a width of 100% of its parent.
If you want to limit it to a particular carousel, modify the selector accordingly.
Another frequently requested TwBs carousel mod is:
.carousel-control-prev,.carousel-control-next {
cursor:pointer;
}
Given bootstrap uses flexbox, you can make the reactstrap carousel images responsive by adding this to your css:
.carousel-item, .carousel-item.active {
align-items:center;
}
This seems to prevent the image height from stretching. Worked for me!
Based on the reactstrap Carousel example 1 on this page https://reactstrap.github.io/components/carousel/
Here's how I got it to be responsive in my use case:
<CarouselItem
onExiting={() => setAnimating(true)}
onExited={() => setAnimating(false)}
key={item.src}
>
<img src={item.src} alt={item.altText} style={{ width: "100%"}}/>
<CarouselCaption captionText={item.caption} captionHeader={item.caption} />
</CarouselItem>
So, passing in style={{ width: "100%"}} to the img tag, made my oversized images fit the screen perfectly and may work for others coming here.
I am very new in angular 2. I am trying to create icon component. The code below works fine in Chrome and Firefox, but doesn't work in Internet Explorer 11.
My component looks as following:
#Component({
selector: 'my-icon',
template: `
<svg *ngIf="_iconClass" class="icon" [ngClass]=_iconClass
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<use xlink:href="" attr.xlink:href="#{{ _iconClass }}" />
</svg>
`
})
export class MyIcon {
private _iconClass: string = '';
#Input() set iconClass(i: string) {
if ((i !== undefined) && (i.indexOf('.ico') > -1)) {
// remove .ico from iconname
this._iconClass = i.substr(0, i.length - 4);
} else {
this._iconClass = i;
}
}
Then, I am using it in another component as following:
<my-icon iconClass="icon--user"></my-icon>
I haven't add all the code, hope it still makes sense. When I have checked in Developer tools, tag <use xlink:href> is empty. My assumption was that IE 11 can't identify attr.xlink:href="#{{ _iconClass }}".
I cannot see what is wrong. I would really appreciate any help.
Edit:
This error is printed to the console
EXCEPTION: TypeError: Unable to get property 'contains' of undefined or null reference in [_iconClass in MyIcon#1:9]
private validateIcon(): void {
if ((this._iconClass !== undefined) && (this._iconClass !== '') && (document.getElementById(this._iconClass) === null)) {
if (this._validateIconRunOnce) {
console.warn('Icon(' + this._iconClass + ') not found.');
this._iconClass = 'not-found';
} else {
// delay validate icon for 3s to wait until the iconlibrary is loaded
this._validateIconRunOnce = true;
setTimeout(() => this.validateIcon(), 3000);
}
}
}
Gunter
Thank you very much for your support. I found a solution here: https://github.com/eligrey/classList.js
To support svg in IE9+ it is required to add classList.js.