How to create a hybrid straight/curved section boundary using svg or css?
P粉920835423
2023-09-02 11:35:13
<p>For my application, I am creating a registration page with non-standard section boundaries. You can see what I'm trying to achieve here:
This is not a simple arc - it has two straight lines and an arc in between. </p>
<p>As far as I know, the best way to achieve something like this is to use SVG. The problem is, the white area will have an image covering the entire area. For demonstration purposes I will use light blue. If you use a standard <code>div</code> with the <code>background-image</code> attribute, the white color of the SVG is opaque, so you get the following result:
</p>
<p>Tip later read the <code>shape-outside</code> and <code>clip-path</code> properties, this is the latest approach I've tried (note I'm using react with styled components ):</p>
<pre class="brush:php;toolbar:false;">const LeftContainer = styled(FlexContainer)`
width: 55%;
height: 100%;
background-color: lightblue;
z-index: 1;
/* background: linear-gradient(360deg, #FFFFFF 24.95%, rgba(255, 255, 255, 0) 50.95%), url(${process.env.PUBLIC_URL}/TestImage.png); */
`;
const RightContainer = styled(FlexContainer)`
width: 45%;
height: 100%;
/* background-color: ${colors.secondary600}; */
float: left;
/* background-image: url(${process.env.PUBLIC_URL}/SignUpBackground.svg); */
background-repeat: no-repeat;
background-size: cover;
background-position: center;
position: relative;
z-index: 5;
clip-path: url(${process.env.PUBLIC_URL}/SignUpBackground.svg#sidebar);
`;</pre>
<p>There is still a gap, but more than that, the bottom third of the SVG shape is cut off:
</p>
<p>The only way I've been able to make the left container fill the extra space is to make the right container <code>position:absolute</code>, but this causes problems with the login form I plan to add to the right ( It doesn't seem to solve the problem of cutting off the bottom third of the svg).</p>
<p>Is there a way to keep the right container in the page flow, display 100% of the svg, and make sure the left container is flush with the right container? </p>
<p>Edit:
This is the SVG code: </p>
<pre class="brush:php;toolbar:false;"><svg width="708" height="1056" viewBox="0 0 708 1056" fill="none" xmlns=" ;http://www.w3.org/2000/svg">
<clipPath id="sidebar">
<path d="M144.5 0H799.5V1056H144.5L23.4254 775.169C0.402533 721.768 -5.09917 662.442 7.71089 605.718L144.5 0Z" fill="#16979A "/>
</clipPath>
</svg></pre>
<p>This is the React component so far (as you can see, early stages of the build): </p>
<pre class="brush:php;toolbar:false;">const SignUpPage = (props) => {
return (
<Container>
<LeftContainer>
{/* Site logo and marketing copy, promo bubbles to go here. This side should be the one to shrink */}
</LeftContainer>
<RightContainer flexDirection="column" justify="center">
{/* Signup/Login form to go here */}
</RightContainer>
</Container>
);
}</pre>
<p>Edit 2:
I've tried implementing the solutions in the answers below, but so far every solution has at least one problem.Starting from ccprog's suggestion, I was a bit unsure as the code didn't seem to match the description of the method, but I tried implementing it and got this result: (code first, then the resulting image) </p>
<pre class="brush:php;toolbar:false;">const Container = styled(FlexContainer)`
height: 523px;
background-image: linear-gradient(360deg, #FFFFFF 24.95%, rgba(255, 255, 255, 0) 50.95%), url(${process.env.PUBLIC_URL}/SignUpImage.jpg);
background-position: top right 282px;
background-size: cover;
background-repeat: no-repeat;
`;
const LeftContainer = styled(FlexContainer)`
flex-grow: 1;
`
const RightContainer = styled(FlexContainer)`
width: 354px;
background-image: url('data:image/svg xml,<svg viewBox="0 0 708 1056" fill="none" xmlns="http://www.w3.org/2000/svg" > 979A"/></svg>' );
background-size: 100% 100%;
`</pre>
<p>As you can see, this doesn't actually fill the full height of the screen, even on the right side, and the left image is really cut off (the left image is an issue with all solutions, Because you will see). </p>
<p>Next, I tried implementing Chrwahl's second solution. This one is somewhat close (the right side looks great), but there are some issues with the image on the left: </p>
<pre class="brush:php;toolbar:false;">const Container = styled(FlexContainer)`
width: 100%;
height: 100vh;
background-image: url(${process.env.PUBLIC_URL}/SignUpBackground.svg),
linear-gradient(360deg, #FFFFFF 24.95%, rgba(255, 255, 255, 0) 50.95%), url(${process.env.PUBLIC_URL}/SignUpImage.jpg);
background-repeat: no-repeat;
background-position: right, left;
background-size: contain, cover;
margin-bottom: 5px;
`;</pre>
<p>I'm not sure if it appears in that image, but the entire left side of the screen is blank, so even though the position is specified as left, the image doesn't seem to start at the left edge. The problem with <code>background-size: 40%, 70%</code> is more serious:
</p>
First some terminology: We call the width of the area covered by the top and bottom of an SVG shape the "right minimum", and the width covered in the middle the "right maximum".
The way I understand your question is that the right area a) has a constant width and b) should always show the full SVG shape. It follows that it must have a constant height and an aspect ratio of 708:1056. This makes it easy to calculate the required dimensions, most importantly the ratio between the minimum on the right and the maximum on the right is 564 : 708.
Now, I would suggest to solve your problem by moving the left image as background image to an outer container element with a width that ensures it is below the curved part, ie. e. 100% minus 564px (or fixed fraction). The left container element containing the promotional content has a width of 100% minus 708px, and the right container has a width of 708px (or a fixed fraction). (For simplicity, containers are identified by class names that match their component names)
You can use other px size values as long as the proportion between them is maintained.
If you don't want to display the full SVG, but just want to make sure the curve on the left remains fully visible, add the following attributes to the root
When changing the aspect ratio of the right container, this will have the same effect as CSS
cover
, and theviewBox
's area will always be to the left. This only works if the aspect ratio is moved to a higher height relative to the width. If the aspect ratio width is increased, the same part of the curve will be cut off at the top and bottom - but the alternative is that it's not wide enough to cover the right side.If you go this route, keep in mind that you only know the width of the area between the largest and smallest right sides if you set a fixed height ahead of time. CSS cannot use an element's height to calculate a width value.