skip to Main Content

For my app, I’m creating a sign-up page with a nonstandard section boundary. You can see the effect I’m trying to achieve here:
enter image description here
It’s not a simple arc — it has two straight lines but also an arc in the middle.

From what I have read, the best way to achieve something like this is with an SVG. The problem is, that white area is going to have an image covering the entire thing. For demo purposes I’ll use a light blue color. If you use a standard div with a background-image property, the white of the SVG isn’t transparent, so you get this:
enter image description here

Cue a couple hours of reading later on shape-outside and clip-path properties, and this is the latest approach I’ve tried (note I’m using React with styled-components):

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);
`;
 

There’s still a gap, but not only that, the SVG shape has the bottom third cut off:
enter image description here

The only way I’ve been able to make the left container fill that extra space is by making the right container position: absolute, but this is going to cause issues with the login form I plan to add to the right side (and it doesn’t seem to solve the issue of cutting off the bottom third of the svg).

Is there a way I can keep the right container in the flow of the page, show 100% of the svg, and ensure the left container is flush with the right container?

EDIT:
Here is the SVG code:

<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>

And here is the React component so far (early stage of build as you can see):

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>
   );
}

2

Answers


  1. First a bit of terminology: let’s call the width of the area covered by the SVG shape at top and bottom the "right side minimum", and the width covered in the middle the "right side maximum".

    The way I understand your question, the right area a) has a constant width and b) should always show the complete SVG shape. From that follows that it must have a constant height and an aspect ratio of 708 : 1056. That makes it easy to compute the needed sizes, the most important being that the ratio between the right side minimum and the right side maximum is 564 : 708.

    Now, I would suggest to solve you problem by moving the left-side image as a background-image to the outer container element, with a width that ensures it goes under the curved part, i. e. 100% minus 564px (or a fixed fraction). The left container element, containing the promo content gets a width of 100% minus 708px, and the right container a width of 708px (or a fixed fraction). (For simplicity, the containers get identified by a class name matching their component name)

    .container {
        display: flex;
        flex-direction: row;
        justify-items: stretch;
        align-items: stretch;
        height: 523px;
        background-image: linear-gradient(360deg, white, red);
        background-position: top right 282px;
        background-size: cover;
        background-repeat: no-repeat;
    }
    .container-left {
        flex-grow: 1;
    }
    .container-right {
        width: 354px;
        background-image: url('data:image/svg+xml,<svg viewBox="0 0 708 1056" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M144.5 0H799.5V1056H144.5L23.4254 775.169C0.402533 721.768 -5.09917 662.442 7.71089 605.718L144.5 0Z" fill="%2316979A"/></svg>');
        background-size: 100% 100%;
    }
    .child {
      box-sizing: border-box;
      height: 100%;
      margin: 2px;
      border: 2px solid blue;
    }
    <div class="container">
      <div class="container-left">
        <div class="child"></div>
      </div>
      <div class="container-right">
        <div class="child"></div>
      </div>
    </div>

    You can use other px size values as long as the ratio between them is maintained.

    And if you do not want to show the full SVG, but only make sure the curve on the left remains completely visible, add the following attribute to the root <svg> element:

    preserveAspectRatio="xMinYMid slice"
    

    When changing the aspect ratio of the right container, this will have the same effect as the CSS cover, plus the area of the viewBox is always ligned up with the left side. This will work only if the aspect ratio will move to a higher height in relation to the width. If the aspect ratio gains in width, equal parts of the curve will be cut of at the top and bottom – but the other choice would be that it isn’t wide enough to cover the right side.

    If you go that route, remember that you can only know the width of the area between maximum and minimum right side if you set a fixed height in advance. CSS just cannot use the height of an element to compute a width value.

    Login or Signup to reply.
  2. You can place both the image and the SVG as a background in CSS. Here are three different examples. In the first I have the same issue as you do. The second will always work, but part of the image is covered by the SVG and cut off. The third is a matter of testing for different sizes.

    Now, my examples are not THE SOLUTION. Takeaway here is: You can have more background images in your CSS. The configuration depends on the size, aspect ratio, the image quality and the purpose of the image. You need to figure out what matches your scenario.

    The SVG in the example looks like this (notice the viewBox has been changed):

    <?xml version="1.0" encoding="UTF-8"?>
    <svg viewBox="0 0 798 1056" xmlns="http://www.w3.org/2000/svg">
      <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"/>
    </svg>
    
    .login {
      width: 400px;
      height: 200px;
      background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2aWV3Qm94PSIwIDAgNzk4IDEwNTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xNDQuNSAwSDc5OS41VjEwNTZIMTQ0LjVMMjMuNDI1NCA3NzUuMTY5QzAuNDAyNTMzIDcyMS43NjggLTUuMDk5MTcgNjYyLjQ0MiA3LjcxMDg5IDYwNS43MThMMTQ0LjUgMFoiIGZpbGw9IiMxNjk3OUEiLz4KPC9zdmc+Cgo='),
      url('https://via.placeholder.com/800x600');
      background-repeat: no-repeat;
      background-position: right, left;
      margin-bottom: 5px;
    }
    
    .size1 {
      background-size: contain, contain;
    }
    
    .size2 {
      background-size: contain, cover;
    }
    
    .size3 {
      background-size: 40%, 70%;
    }
    <div class="login size1"></div>
    <div class="login size2"></div>
    <div class="login size3"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search