There's lots of techniques that cover the simplicity of the question, here are my requirements:
I'd like an <hr /> element to be visible, with a portion of it cut out (e.g.; fully transparent)
The width of the <hr /> is unknown
The cutout region has fixed dimensions and must be centered on top of the <hr />
Use 1x <hr /> element
Supported in IE11 and Safari 11, as well as modern browsers
Due to the browser support, I think I am left with using clipPath within an SVG and setting that as the clipping region via CSS on the <hr /> element.
The following demo is not tested in IE/Safari yet and it highlights my attempts to firstly draw an SVG shape with a portion cut out. That part is nearly fine apart from my requirements #2 and #3 because I don't yet have a fluid filling path with a fixed and centred second path inside it.
Requirement #1 currently fails completely, when I convert the path inside the SVG into a clipPath and then assign that to the hr /> element.
Codepen demo: https://codepen.io/davewallace/pen/WNNRMoR
Markup:
<p>1. Aspect ratio in action, box is correctly centered, but I need the black region to stretch all the way to the far left and right edges, leaving the inner cut-out box in the middle.</p>
<div>
<hr />
<svg xmlns="http://wwww3org/2000/svg" height="32" width="100%" viewBox="0,0,10,10">
<path d="M 0,0 h 10 v 10 h -10 z
M 2,2 v 6 h 6 v -6 z" />
</svg>
</div>
<p>2. So I tried removing the aspect ratio. That sort of helped, but I need the inner cut-out box to be a fixed width and centered.</p>
<div>
<hr />
<svg xmlns="http://wwww3org/2000/svg" height="32" width="100%" viewBox="0,0,10,10" preserveAspectRatio="none">
<path d="M 0,0 h 10 v 10 h -10 z
M 2,2 v 6 h 6 v -6 z" />
</svg>
</div>
<p>3. Regardless of the stretching accuracy of the two techniques above, I expected the supplied paths, converted into a clipPath, to hide the centre part of the HR element, leaving only its left/right sides visible.</p>
<div>
<hr class="clipped" />
<svg xmlns="http://wwww3org/2000/svg" height="32" width="100%" viewBox="0,0,10,10">
<defs>
<clipPath id="square">
<path d="M 0,0 h 10 v 10 h -10 z
M 2,2 v 6 h 6 v -6 z" />
</clipPath>
</defs>
</svg>
</div>
CSS (mostly to illustrate):
div {
position: relative;
border: 1px solid red;
margin: 50px;
padding: 20px;
background: #999;
}
hr {
height: 5px;
background: lime;
&.clipped {
clip-path: url(#square);
}
}
svg {
position: absolute;
left: 0;
top: 20%;
border: 1px dotted red;
}
Research so far:
https://css-tricks.com/clipping-masking-css/
https://css-tricks.com/cutting-inner-part-element-using-clip-path/
How can I cut one shape inside another?
Alternative approaches so far:
Use flexbox and have 1 <hr />, a gap, and then another element like a <div /> finishing off the second half of the effect. So it's not 'cutting a hole' in the <hr /> but stopping and starting it visually. This approach, in my context, would need some magic numbers and isn't so clean. Pretty sure it's still accessible in that I am still using 1x <hr /> element mostly as it is intended to be used.
Nothing else so far, but this is to achieve a "fancy horizontal rule" effect, where someone can drop their image/SVG asset into the middle of the horizontal rule without worrying about the horizontal line going under the asset. I also don't know what the page background colour is, no assumptions can be made about that.
Thank you!
I suppose your hr element will have a solid coloration as background. Considering this you can play with background to coloration to color only the needed part keeping the middle on transparent.
I will rely on calc() that should work on IE11 but I cannot test it.
hr {
height:10px;
margin:10px 0;
border:none;
background:
linear-gradient(blue,blue) left,
linear-gradient(blue,blue) right;
background-size:calc(50% - 10px) 100%; /* Cut 20px from the middle */
background-repeat:no-repeat;
}
body {
background:pink;
}
<hr>
You can also add some border if you want to have a hole in your element:
hr {
height:20px;
margin:10px 0;
border-top:10px solid blue;
border-bottom:10px solid blue;
background:
linear-gradient(blue,blue) left,
linear-gradient(blue,blue) right;
background-size:calc(50% - 10px) 100%; /* Cut 20px from the middle */
background-repeat:no-repeat;
}
body {
background:pink;
}
<hr>
Just use clip-path and calc().
I used this tool to make a relative path, and then I added manually the calc().
https://bennettfeely.com/clippy/
hr {
clip-path: polygon(0% 0%, 0% 100%, calc(50% - 10px) 100%, calc(50% - 10px) calc(50% - 10px), calc(50% + 10px) calc(50% - 10px), calc(50% + 10px) calc(50% + 10px), calc(50% - 10px) calc(50% + 10px), calc(50% - 10px) 100%, 100% 100%, 100% 0%);
height:40px;
background: black;
}
body {
background: url(http://placekitten.com/200/300);
margin: 10px;
}
<hr>
Related
UPDATE: I had previously found a way to accomplish this using CSS, but the slope of the line is jagged and the aspect ratio of the triangle is not consistent for all widths. Here's a Codepen of that solution.
How can I create the effect where the top of the footer slopes upward? Most footers have a simple straight horizontal line along the top of the footer div, but I need to create an effect where the line slopes upward. Here are some different approaches:
PNG image with transparency.
CSS only
SVG
I prefer not to use a PNG image and tried using straight CSS and am now trying it using SVG. The height of the triangular shape should be no more that 200 pixels at the full width of 1440 pixels.
.main {
background: #ccc;
}
.right-triangle {
display: block;
}
.footer {
background: #333;
color: #fff;
}
<div class="main">End of main section be flush with the div below.</div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="right-triangle">
<polygon points="50 25, 100 100, 0 100" />
</svg>
<div class="footer">
Next section needs to be flush with the triangle with no gap in between.
</div>
The code below should do what you want. The key is to set the height and width separately and NOT preserve the aspect ratio for the SVG.
You might need to play with values in the max function to get the narrow screen versus wide screen effects you want. And/or, change max-height to height.
CSS
.main {
background: #ccc;
}
.right-triangle {
display: block;
width: 100%;
max-height: max(20px, calc(200vw / 1440 ));
}
.footer {
background: #333; color: #fff;
}
HTML
<div class="main">
End of main section be flush with the div below.</div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"
class="right-triangle"
preserveAspectRatio="none">
<polygon points="100 0, 100 100, 0 100" />
</svg>
<div class="footer">
Next section needs to be flush with the triangle with no gap in between.
</div>
(I am on a mobile phone, so, sorry but it is bit difficult posting this how I would like to.)
In an SVG gradient you can set the start x y and end x y position. Is it possible to do that in CSS linear gradient but using unanchored, independent start and end positions (images shown below)?
Here is my CSS linear gradient:
#rectangle {
width: 100%;
height: 200px;
position: absolute;
top: 0;
left: 0;
background: linear-gradient(225deg, rgba(255,255,255,1) 0%, rgba(250,0,0,1) 27.59%, rgba(108,22,95,1) 76.35%, rgba(39,32,32,1) 100%)
}
<div id="rectangle">
</div>
Here is the expected output in a square:
Expected output in a rectangle
I've been referencing this page on MDN and this page on W3C.
The SVG contains the orientation of the gradient
x1="1" x2="0.5" y1="0" y2="0.5"
The element also takes several other attributes,
which specify the size and appearance of the gradient. The orientation
of the gradient is controlled by two points, designated by the
attributes x1, x2, y1, and y2. These attributes define a line along
which the gradient travels. The gradient defaults to a horizontal
orientation, but it can be rotated by changing these. Gradient2 in the
above example is designed to create a vertical gradient.
- from https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Gradients
From other documentation:
X and Y position of the start of the gradient line, as a multiple of
the object's bounding box: X=0 indicates the left edge of the bounding
box and X=1 indicates the right edge. The gradient line may start or
end outside the object's bounding box, so values may be < 0 or > 1.
There also may be going a pre transform / post transform issue.
In my project I get the width and height of the square / rectangle, the start and end points (gradient lines), the color stop colors and the color stop ratios. The gradient lines are different each time.
You can consider the use of calc() where you will combine pixel and percentage value. The percentage value will define the reference and the pixel will define the gradient length and you multiple the length with the percentage of each color:
.rectangle {
width: 200px;
height: 100px;
display:inline-block;
border:1px solid;
background: linear-gradient(225deg,
rgba(255,255,255,1) calc(50% - 70px*(1 - 0)),
rgba(250,0,0,1) calc(50% - 70px*(1 - 0.2759)),
rgba(108,22,95,1) calc(50% - 70px*(1 - 0.7635)),
rgba(39,32,32,1) calc(50% - 70px*(1 - 1)))
}
<div class="rectangle">
</div>
<div class="rectangle" style="width:100px;">
</div>
<div class="rectangle" style="width:300px;">
</div>
In the above I made the end point at 50%. You can do the same for the starting point:
.rectangle {
width: 200px;
height: 100px;
display:inline-block;
border:1px solid;
background: linear-gradient(225deg,
rgba(255,255,255,1) calc(50% + 70px*0),
rgba(250,0,0,1) calc(50% + 70px*0.2759),
rgba(108,22,95,1) calc(50% + 70px*0.7635),
rgba(39,32,32,1) calc(50% + 70px*1))
}
<div class="rectangle">
</div>
<div class="rectangle" style="width:100px;">
</div>
<div class="rectangle" style="width:300px;">
</div>
I have a container transformed with transform: skew(0deg, -3deg )translateY(-6vh), but I'm using it for a footer, so I want it to be completely flat at the bottom part. How can I acheive it without covering it up with another container with the same background colour? (I don't want things to mess up the responsiveness).
I would use the ::before psuedo element. I couldn't figure out how to get the ::before element to go under the main one, so you lose a little space, but it's not too bad.
Using ::before horribly failed. Plus, there is some oddities with using transform which can be seen if you just put a background color on the element and use a sufficiently wide screen.
So, rather than fight with that, I would just use an SVG to give you that slant you want. There was an odd space between the svg and div, so I used positioning to get around that.
You can play with the values to get the slant how you like, but be advised that it will vary based on the screen width.
#footer {
position:relative;
overflow:hidden;
}
svg {
width: 100%;
fill: green;
max-height: 50px;
position:absolute;
top:0;
}
#footerContent {
margin-top:49px;
height: 100px;
background: orange;
}
<div id="footer">
<svg viewBox="0 0 100 20" preserveAspectRatio="none">
<polygon points="0,20 100,20 100,0" />
</svg>
<div id="footerContent"></div>
</div>
I am working on svg image (as shown in the screenshot marked by an arrow having four triangles) html code as show below belonging to the webpage in which I want to increase the height of it.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30">
<style>.path-one,.path-two{fill-rule:evenodd;clip-rule:evenodd;fill:#00afc9}.path-two{opacity:.4;fill:#93c83d}</style>
<path class="path-one" d="M30 30H0V0"></path>
<path class="path-two" d="M0 30V0h30"></path>
</svg>
I tried adding inline width="150px" and height="150px" in svg tag but it doesn't seem to work.
Problem Statement:
I am wondering what changes I should make in the code above so that the height of the svg image gets changed
You can achieve the same result using CSS and it will be easier to handle:
.box {
display:inline-block;
width:150px;
height:150px;
background:
linear-gradient(to top left ,transparent 49.3%,rgb(147, 200, 61,0.4) 50%),
linear-gradient(to bottom left,transparent 49.3%,#00afc9 50%);
}
<div class="box">
</div>
You can also integrate it as background for your black bar:
.box {
height:60px;
background:
linear-gradient(to top left ,transparent 49.3%,rgb(147, 200, 61,0.4) 50%),
linear-gradient(to bottom left,transparent 49.3%,#00afc9 50%),
#000;
background-size:60px 100%;
background-repeat:no-repeat;
}
<div class="box">
</div>
apply it on the svg element:
svg { width: 150px; height: 150px }
Please note that, the svg image is actually taking the height and width that you want to set by using height and width properties only. The problem however lies in you paths. You can add a background-color to svg element to verify that it actually is changing the height and width.
<svg xmlns="http://www.w3.org/2000/svg" height="300" width="150"
viewBox="0 0 30
30" enable-background="new 0 0 311.7 311.5">
<path fill="red" class="path-one" d="M30 30H0V0"></path>
<path fill="blue" class="path-two" d="M0 30V0h30"></path>
</svg>
<!-- CSS Code-->
<style>
svg {
background-color: black;
}
</style>
A handly website to quickly play around SVG images is :
https://www.rapidtables.com/web/tools/svg-viewer-editor.html
Make good use of it.
Thank you for getting into this question.
i want to add a border/line that have one side incline that works as a divider between image and title. Below is the screenshot.
here is the html i have right now
<div class="entry-wrap">
<img class="x-img x-img-thumbnail" src="{image-src}" alt="Place Alt Text Here">
<div class="cut-border"></div>
<div class="x-recent-posts-content">
<h5>Title</h5>
</div>
Thank you so much for your effort.
Its possible using css, but it would probably be easier if you added that border in photoshop or something and insert it on your page
Note: The shape I use in these example does not match the one in the question. Mainly in that the shape on the question does not go down to the corner. Another difference is that I used a fixed height to define the "border" (it measures 5px vertically everywhere) while the one in the question seems to have a fixed width that takes into account the angle on the "stroke". These are details that make the construction of the polygons a bit more complicated, yet do not invalidate the presented approaches.
CSS Clip-Path
What you want can be done using CSS Clip-Path. Which, by itself will make the cut you want in the image, and also will make the cuts in the div that stands in for border.
Some tweaks are necesary to place the objects ontop of each other (clip path does not affect box sizing).
img {
width:250px;
height:250px;
-webkit-clip-path: polygon(100% 0, 100% 100%, 75% 75%, 0 75%, 0 0);
clip-path: polygon(100% 0, 100% 100%, 75% 75%, 0 75%, 0 0);
display:block;
}
.cut-border {
width:250px;
height: calc(250px * 0.25);
background-color: red;
-webkit-clip-path: polygon(75% 0, 100% calc(100% - 5px), 100% 100%, 75% 5px, 0 5px, 0 0);
clip-path: polygon(75% 0, 100% calc(100% - 5px), 100% 100%, 75% 5px, 0 5px, 0 0);
position:relative;
top: calc(250px * -0.25);
}
.x-recent-posts-content {
position:relative;
top: calc(250px * -0.5);
}
<div class="entry-wrap">
<img src="http://lorempixel.com/250/250/city/" alt="lorempixel"><div class="cut-border"></div>
<div class="x-recent-posts-content">
<h5>Title</h5>
</div>
</div>
One drawback I see is that it does not get pixel perfect cuts (you can see the pieces do not match perfectly, this deffect may or not be visible depending on zoom level). It is possible to hide it, I did not do any of that in the examples above.
Another drawback is that will not work in IE or Edge.
See browser support.
SVG
Instead of trying to solve this with CSS, we can have a stab at it with SVG:
.x-recent-posts-content {
position:relative;
top: calc(250px * -0.25);
}
<svg width="250" height="250" viewBox="0 0 250 250" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="img" patternUnits="userSpaceOnUse" width="250" height="250">
<image xlink:href="http://lorempixel.com/250/250/city/" x="0" y="0" width="250" height="250" />
</pattern>
</defs>
<polygon fill="url(#img)" points="250,0 250,250, 187.5,187.5 0,187.5 0,0"></polygon>
<polygon fill="#f00" points="187.5,187.5 250,245 250,250 187.5,192.5 0,192.5 0,187.5" />
</svg>
<div class="x-recent-posts-content">
<h5>Title</h5>
</div>
See browser support.