CSS how to warp/bend an image or div? - css
Hi,
Is it possible to achieve this effect with CSS only?
As you can see, the image on top is distorted along with the text inside to look like the one below. It may be a div or an image. I have been researching on transform but found nothing about curves.
This is NOT a duplicate because I am not asking how to curve the text only but the div container as well as in case of an image.
Thank you.
I don't know if you would technically qualify this as "CSS only" since it is using an SVG filter, but I think it could be made to achieve the type of warping you want.
.warped {
display: inline-block;
background-color: yellow;
padding: 4px;
filter: url(#displacement);
}
#filterSource {
display: none;
}
<span class="warped">Warped Text!</span>
<div>
<svg id="filterSource" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="displacement" filterUnits="userSpaceOnUse">
<!-- this is just a base64 encoded PNG with a simple linear gradient -->
<!-- this may not be exactly what you want, but you can adjust the R and B channels to displace the element however you like. -->
<feImage href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAdhAAAHYQGVw7i2AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAGlJREFUaIHtz6ENwEAMxVBfUWn3H7Kw8LpCdMjAT/osIF7AZuAGnsMt4D3cN3kOuIZ3eoXYFGJTiE0hNoXYFGJTiE0hNoXYFGJTiE0hNoXYFGJTiE0hNoXYFGJTiE0hNoXYFGJTiE0hNj9ceBBjuV6HJAAAAABJRU5ErkJggg==" result="dispMap" />
<feDisplacementMap
in="SourceGraphic"
in2="dispMap"
scale="10"
xChannelSelector="B"
yChannelSelector="R" />
</filter>
</defs>
</svg>
</div>
Here's a nice tutorial on some cool effects you can achieve with this technique: https://www.creativebloq.com/how-to/add-svg-filters-with-css
Related
IE and Edge ignore absolute position of svg [duplicate]
I decided to switch to svg symbols for one of my projects - but need them to be responsive. The main idea is not to have multiple http requests, so I was thinking of merging all SVGs into one SVG, define symbols and use them as follows: <svg style="display:none;"> <defs> <symbol id="mys"> <path fill-rule="evenodd" clip-rule="evenodd" fill="#3F77BC" d="M222.1,77.7h-10.3c0.1-0.8,0.2-1.4,0.2-2.3 c0-8.5-6.9-15.4-15.4-15.4c-8.5,0-15.4,6.9-15.4,15.4c0,0.9,0.1,1.5,0.2,2.3h-9.3v4h-24.9v-5.2H89.4c0-0.3,0-0.6,0-0.9 C89.4,67.1,82.5,60,74,60s-15.4,6.9-15.4,15.4c0,0.3,0,0.6,0,0.9h-6.2V60.7h4.3l5.3-5.3h22.8L74.3,44.9l-13.5-3.6l0.5-1.7 l-16.5-4.4c-0.3,0.1-0.7,0.2-1,0.2l0,21.4h2v7.2c0,0-2,0.6-1.9,1.3c0.1,0.7,4.1,2.6,3.4,5.5c-0.6,2.9-1.6,4.8-4.4,4.5 c-2.7-0.3-3.4-1.4-3.4-2.6c-0.1-1.2,0-3,0-3L38,67.9c0,0,2-0.5,2.6,1.1c0.6,1.5-0.2,2.7,0.6,3.5c0.8,0.8,4.1,1.4,4.1-1.1 c0-2.5-0.5-2.4-2.1-3.6c-1.7-1.2-3.4-2.8-3.4-3.3c0-0.5-0.1-7.7-0.1-7.7h2.1l0-21.7c-1.4-0.7-2.5-2.1-2.5-3.8 c0-2.3,1.9-4.2,4.2-4.2c2,0,3.6,1.4,4.1,3.2l15.3,4.1l0.4-1.6l55.8,15.1h28.1c0,0,0-23.5,0-26.2c0-2.7,2.1-2.6,2.1-2.6 s32.5-0.5,35.1,0.5c2.7,1,3.3,3.7,3.3,3.7h-2l5,11.6c0,0,7.3,4.6,17.6,7.6c10.3,3,13.6,7.6,13.6,7.6l-1,17.6l1.3,2V77.7z M81.5,46.8l8.6,8.6h9.3l2.9-2.9L81.5,46.8z M175.5,25l-17.4-0.1v12.6h9.6l2.7,2.7h6.6L175.5,25z M183,23.7h-4c0,0,2,6.6,3,9.9 s0.9,4.2,2.7,4.2c1.9,0,4.2,0,4.2,0L183,23.7z M74.2,63.8c6.8,0,12.3,5.5,12.3,12.3S81,88.4,74.2,88.4c-6.8,0-12.3-5.5-12.3-12.3 S67.4,63.8,74.2,63.8z M196.6,63.8c6.8,0,12.3,5.5,12.3,12.3s-5.5,12.3-12.3,12.3s-12.3-5.5-12.3-12.3S189.8,63.8,196.6,63.8z"/> </symbol> </defs> </svg> <div style="position:relative;width:100%;background:blue;"> <svg class="mys" viewBox="0 0 254 108" preserveAspectRatio="xMaxYMax meet" style="width:100%;"> <use xlink:href="#mys"></use> <svg> </div> Here is a jsfiddle, check the different behaviour in IE (I checked 11 but read that 9 has multiple issues as well): http://jsfiddle.net/ws472q71/ For the life of me I can't get this to work properly. The above code works correctly in Firefox and Chrome, but fails in IE. I read about IE issues, but I couldn't find anything that works. What am I doing wrong? Is there any other similar solution that can merge SVGs into one file and use them as responsive images? Thanks!
As you have discovered, IE has a bug where it doesn't scale the SVG properly if you don't provide both the width and height. To get it working in IE, you can use a trick discovered (?) by Nicolas Gallagher. http://nicolasgallagher.com/canvas-fix-svg-scaling-in-internet-explorer/ The trick uses a <canvas> element. IE does properly scale canvas elements. So if you place one in the <div> with the SVG, the SVG will end up the correct size. You just need to give the canvas the same aspect ratio as your SVG. <div style="position:relative;width:100%;background:blue;"> <canvas width="254" height="108"></canvas> <svg class="mys" viewBox="0 0 254 108" preserveAspectRatio="xMaxYMax meet"> <use xlink:href="#mys"></use> </svg> </div> with CSS canvas { display: block; width: 100%; visibility: hidden; } svg { position: absolute; top: 0; left: 0; width: 100%; } canvas { display: block; width: 100%; visibility: hidden; } svg { position: absolute; top: 0; left: 0; width: 100%; } <svg style="display:none;"> <defs> <symbol id="mys"> <path fill-rule="evenodd" clip-rule="evenodd" fill="#3F77BC" d="M222.1,77.7h-10.3c0.1-0.8,0.2-1.4,0.2-2.3 c0-8.5-6.9-15.4-15.4-15.4c-8.5,0-15.4,6.9-15.4,15.4c0,0.9,0.1,1.5,0.2,2.3h-9.3v4h-24.9v-5.2H89.4c0-0.3,0-0.6,0-0.9 C89.4,67.1,82.5,60,74,60s-15.4,6.9-15.4,15.4c0,0.3,0,0.6,0,0.9h-6.2V60.7h4.3l5.3-5.3h22.8L74.3,44.9l-13.5-3.6l0.5-1.7 l-16.5-4.4c-0.3,0.1-0.7,0.2-1,0.2l0,21.4h2v7.2c0,0-2,0.6-1.9,1.3c0.1,0.7,4.1,2.6,3.4,5.5c-0.6,2.9-1.6,4.8-4.4,4.5 c-2.7-0.3-3.4-1.4-3.4-2.6c-0.1-1.2,0-3,0-3L38,67.9c0,0,2-0.5,2.6,1.1c0.6,1.5-0.2,2.7,0.6,3.5c0.8,0.8,4.1,1.4,4.1-1.1 c0-2.5-0.5-2.4-2.1-3.6c-1.7-1.2-3.4-2.8-3.4-3.3c0-0.5-0.1-7.7-0.1-7.7h2.1l0-21.7c-1.4-0.7-2.5-2.1-2.5-3.8 c0-2.3,1.9-4.2,4.2-4.2c2,0,3.6,1.4,4.1,3.2l15.3,4.1l0.4-1.6l55.8,15.1h28.1c0,0,0-23.5,0-26.2c0-2.7,2.1-2.6,2.1-2.6 s32.5-0.5,35.1,0.5c2.7,1,3.3,3.7,3.3,3.7h-2l5,11.6c0,0,7.3,4.6,17.6,7.6c10.3,3,13.6,7.6,13.6,7.6l-1,17.6l1.3,2V77.7z M81.5,46.8l8.6,8.6h9.3l2.9-2.9L81.5,46.8z M175.5,25l-17.4-0.1v12.6h9.6l2.7,2.7h6.6L175.5,25z M183,23.7h-4c0,0,2,6.6,3,9.9 s0.9,4.2,2.7,4.2c1.9,0,4.2,0,4.2,0L183,23.7z M74.2,63.8c6.8,0,12.3,5.5,12.3,12.3S81,88.4,74.2,88.4c-6.8,0-12.3-5.5-12.3-12.3 S67.4,63.8,74.2,63.8z M196.6,63.8c6.8,0,12.3,5.5,12.3,12.3s-5.5,12.3-12.3,12.3s-12.3-5.5-12.3-12.3S189.8,63.8,196.6,63.8z"/> </symbol> </defs> </svg> <div style="position:relative;width:100%;background:blue;"> <canvas width="254" height="108"></canvas> <svg class="mys" viewBox="0 0 254 108" preserveAspectRatio="xMaxYMax meet"> <use xlink:href="#mys"></use> </svg> </div> The trick works whether you are trying to get it to match a width or a height.
On a side note to help anyone struggling to implement this fix or finding its not working with external svg files rather than in-page svg markup You need to ensure that when editing your svg file in a text editor it is not missing viewBox or preserveAspectRatio attributes in the opening <svg> tag. If these are missing regardless of what fixes you apply the svg will still not scale in IE - even though it'll scale in other browsers without issue. If these options are set you can define the width/height on the image element used to pull in the svg to 100% and use max-width or max-height to limit the scaling and it will perform as expected. Though - you could still get some alignment issues.
Nicolas Gallagher's solution works great, however, I ran into some responsive issues as I decreased the viewport. I thought I would pass along the fix I used: <div class="parent-div"> <canvas width="3" height="1"></canvas> <svg class="mys" viewBox="0 0 254 108"> <use xlink:href="#mys"></use> </svg> </div> I updated the "parent-div" with max-width:100%; .parent-div{ position: relative; display: inline-block; height: 550px; max-width: 100%; } This will not solve all your scaling issues. You will still have to use media queries to change the height as you go, but at least the svg doesn't blow out its container. Hope this helps someone.
This can be rewritten like so if you're working with <img> HTML <div class="ie-svgHeight"> <img src="path.svg" class="ie-svgHeight-img"> <canvas class="ie-svgHeight-canvas"></canvas> </div> SCSS .ie-svgHeight { position: relative; &-canvas { display: block; visibility: hidden; position: absolute; top: 0; left: 0; height: 100%; } &-img { height: 100%; } }
Canvas not rendering inside g with transform
please save my sanity! <svg version="1.1" xmlns="http://www.w3.org/2000/svg" id="sake" stroke-opacity="0.3" style="width: 100%; height: 100%;"> <g id="1" class="squaregroup" transform="translate(300, 20)"> <g id="square_main_1" class="square_main" transform="translate(250, 50)"> <foreignObject class="" id="fo_1" style="width: 500px; height:500px;"> <div id="globe" style="width:100%; height:100%" ></div> </foreignObject> </g> </g> </svg> A working simplified jsfiddle https://jsfiddle.net/n6erd5dq/6/ The canvas works (albeit the globe is only a few pixels in the bottom right corner) and draws the right ThreeJS world, but it never renders inside the parent DIV. If you inspect the body elements, you can see the DIV is translated right and down a bit. I've tried so many options of position, absolute, max-width, div clear, changing hierarchy, etc, every trick I know. From what I see, canvas should honour a foreignObject which honours transform/translate. Nor can I find any other question on this, so I wonder if I'm doing something SO wrong that no one else has come across this? I know an alternative is to have one canvas for the entire screen and then multiple viewports (?) for each little image, but given the rest of the project I'm trying to stay away from this. e.g. https://threejs.org/examples/webgl_multiple_elements.html Many Thanks Andy
Doesn't (desktop browser) Safari support !important - directive in css - when inline style applied to SVG? [duplicate]
The dilemma: make a full window svg image that fills WITH aspect distortion, WITHOUT using an SVG tag. Why no svg tag? Because I intend on swapping out the SVG later (if not frequently) in the life of the page, and I have not found an easy way to do that. The failed attempts: <!-- for the record, my style are in a css file, for example purposes they are style attrs--> <!-- Working in Webkit but not in firefox, in firefox blocks stretching and places the svg in the middle of the tag--> <img src="my.svg" style="width:100%;height:100%; position:fixed;top:0;left:0;bottom:0;right:0;" /> <!-- Both Webkit and Firefox block distortion, so the svg appears centered in the div rather than conforming to the div--> <div style="width:100%;height:100%;position:fixed;top:0; left:0;bottom:0;right:0;background-size:cover; background-image:url(my.svg);" /> I have also tried background-size:contain; background-size:cover; background-size:100% 100%; background-postion: center center; but no luck.
I got this to work in Firefox, Chrome, and Safari using <img src="my.svg" style="width:100%;height:100%;position:fixed;top:0;left:0;bottom:0;right:0;" /> The trick was to make sure the SVG I was displaying had preserveAspectRatio="none" set in the root. Also, I had to either delete the viewBox in the SVG, or make sure it tightly cropped the image content. For example: <svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 5 3"> <desc>Flag of Germany</desc> <rect id="black_stripe" width="5" height="3" y="0" x="0" fill="#000"/> <rect id="red_stripe" width="5" height="2" y="1" x="0" fill="#D00"/> <rect id="gold_stripe" width="5" height="1" y="2" x="0" fill="#FFCE00"/> </svg> Hopefully you have control over the content of the SVG files you are trying to display. :-)
Here's a jQuery solution. As you can see, I'm using it with an SVG without <svg> The css #bgImage{ position:absolute; left:0; top:0; } The html <object width="10" height="10" id="bgImage" data="resources/runner.svg" type="image/svg+xml"></object> The javascript //resize the background image function resizeImage($selection){ //get the ratio of the image var imageRatio = $selection.width() / $selection.height(); //get the screen ratio var screenRatio = $(window).width() / $(window).height(); //if the image is wider than the screen if(imageRatio > screenRatio){ $selection.height($(window).height()); //set image height to screen height $selection.width($(window).height()*imageRatio); //set the correct width based on image ratio } //if the screen is wider than the image else{ $selection.width($(window).width()); //set the image width to the screen width $selection.height($(window).width()/imageRatio); //set the correct image height based on the image ratio } } Run this whenever you want to resize the image, typically on "onresize" and "onload" $(window).resize(function(){ resizeImage($("#bgImage")); }
SVG - Accessing individual nodes on xlink:href external source
I was looking at Chris Coier's SVG tricks on CSS-tricks.com and also recently saw him at a conference where he talked about the powers of SVGs and how you can keep all assets in one external svg file. <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="beaker" viewBox="214.7 0 182.6 792"> <!-- <path>s and whatever other shapes in here --> </symbol> <symbol id="shape-icon-2" viewBox="0 26 100 48"> <!-- <path>s and whatever other shapes in here --> </symbol> </svg> Then, you could just use it like this: <svg class="icon"> <use xlink:href="#shape-icon-1" /> </svg> <svg class="icon"> <use xlink:href="#shape-icon-2" /> </svg> Sounds great! BUT, I want to be able to access individual nodes in each symbol and altering them with CSS like I normally would if the SVG was inline in the HTMl. Take a look at this CodePen: http://codepen.io/chriscoyier/pen/Hwcxp I thought I could do this, but I can't get it to work: .icon path{ fill: green; } This does, but this alters the actual source svg #beaker path { fill: green; } What I want to do is reuse a graphical element in a grid. And on hover, alter a node in the svg. But only on the node in that particular parent. Not all of them.
Firefox does some unknown thing where you can style it this way. edit: To be more precise: Firefox seems to turn that symbol kinda into in the DOM. http://codepen.io/Type-Style/pen/EaGbam .hoverME:hover path, .hoverME:hover circle { fill: red; } This also works with an external file. (Unfortunatly it does not with crossDomain Files) "But you can insert just the class name of the path. That will work." I mean as long as you stay within the SVG with your selectors it will work. circle:hover, path:hover { fill: red; }
Precise SVG mouseovers in CSS and HTML
I have a geometic shape that I would like to fill in, pictured When the mouse is hovered over each area, I would like it to fill in, pictured here. Unfortunately, when I add in the rest of the shapes, my code does not work, as my browser is giving each shape a bounding box that covers the rest of the shapes. How can I make the mouseover shape of my svg precise and not a box? Here is my HTML code: <object data="images/logo/middle.svg" type="image/svg+xml" class="middlesvg hoversvg" > <!-- only the middle is shown for brevity --> </object> CSS .hoversvg { opacity: 0; } .hoversvg:hover{ opacity: 1; }
You could do it straight in the SVG, no CSS required. Draw each segment as its own polygon or path, and add a set attributeName tag into it: <path … id="path1"><set attributeName="opacity" from="0" to="1.0" begin="path1.mouseover" end="path1.mouseout"/></path> <path … id="path1"><set attributeName="opacity" from="0" to="1.0" begin="path2.mouseover" end="path2.mouseout"/></path> etc. This page has a bit more detail http://www.ibm.com/developerworks/library/x-svgint/ (scroll down to Events)
You'd need to implement the hovering within the middle.svg file. That way you can target the specific shape you want to change on hover.
Give each <path> in the SVG an id, like: <svg xmlns="http://www.w3.org/2000/svg"> <path id="first-path"/> <path id="second-path"/> </svg> Then you can select the individual paths in JS (e.g. document.querySelector('#first-path')) and do whatever you want with it. To fill in the inside of the path, you could do something like this in your CSS: #first-path { cursor: pointer; pointer-events: fill; } #first-path:hover { fill: rgba(255,255,255,0.5); }