Search code examples
csscss-shapes

Content Inside a Shape


I want to get my footer to look like this Image. 4 columns inside a triangle shape.

enter image description here

However for some reason it appears that all four columns get stacked on-top of each other, which I confirmed by slight changing the top margin. When I comment out the #right_triangle, I get 4 columns, as you would expect. I believe its the border on the actual triangle that's doing it, but I cant figure out a way to do it or get around it.

Below is the code I'm using.

#right_triangle {
  width: 0;
  height: 0;
  border-bottom: 300px solid #009933;
  border-right: 2000px solid transparent;
}
#footer_column1 {
  margin-top: 200px;
  width: 25%;
  float: left;
}
#footer_column2 {
  margin-top: 200px;
  width: 25%;
  float: left;
}
#footer_column3 {
  margin-top: 200px;
  width: 25%;
  float: left;
}
#footer_column4 {
  margin-top: 200px;
  width: 25%;
  float: left;
}
<div id="footer">
  <div id="right_triangle">
    <div id="footer_column1">Hello</div>
    <div id="footer_column2">Hello</div>
    <div id="footer_column3">Hello</div>
    <div id="footer_column4">Hello</div>
  </div>
</div>


Solution

  • Reason:

    The problem as you've correctly guessed is with the #right_triangle but it is not because of border. It is because of width: 0 on this element and width: 25% on child #footer_column* elements. May be you overlooked it (or maybe you haven't understood the concept fully) but a percentage width on a child element would use the parent's set width as reference for calculation. Thus the width of all child elements are nothing but 0px. Since they are floated, the second and subsequent elements are offset from their previous sibling only by the width of the previous element(s) and they don't have any margin on the right also. So, effectively they are all placed at 0px on the left (on top of each other).

    Again since they are floated they stay in same line unless their width exceeds a line's width. Here the width is also not more than a line's width (which is the parent's width). If you set even width: 1px to any of the first three elements, you'd notice that the others get pushed to the next line.


    Solution:

    Given how you need the screen's width to be split evenly across the 4 columns (from the image) and without changing your overall approach, you could make use of any one of the following solutions:

    1. Give all the #footer_column* elements, a width in viewport units instead of in percentages, set display: inline-block instead of float: left and add white-space:nowrap to the parent. All these will make them get displayed on the same line without changing your markup.

      #right_triangle {
        width: 0;
        height: 0;
        white-space: nowrap;
        border-bottom: 300px solid #009933;
        border-right: 2000px solid transparent;
      }
      #footer_column1 {
        margin-top: 200px;
        width: 25vw;
        display: inline-block;
      }
      #footer_column2 {
        margin-top: 200px;
        width: 25vw;
        display: inline-block;
      }
      #footer_column3 {
        margin-top: 200px;
        width: 25vw;
        display: inline-block;
      }
      #footer_column4 {
        margin-top: 200px;
        width: 25vw;
        display: inline-block;
      }
      <div id="footer">
        <div id="right_triangle">
          <div id="footer_column1">Hello</div>
          <div id="footer_column2">Hello</div>
          <div id="footer_column3">Hello</div>
          <div id="footer_column4">Hello</div>
        </div>
      </div>

    2. Make all the 4 footer column elements as children of footer element instead of #right_triangle. Since the footer is a block element, it gets 100% of the screen width by default and so it would be split evenly across the 4 children. Note that you would have to absolutely position the #right_triangle and use z-index: -1 on it for this method.

      #footer {
        position: relative;
      }
      #right_triangle {
        position: absolute;
        width: 0;
        height: 0;
        border-bottom: 300px solid #009933;
        border-right: 2000px solid transparent;
        z-index: -1;
      }
      #footer_column1 {
        margin-top: 200px;
        width: 25%;
        float: left;
      }
      #footer_column2 {
        margin-top: 200px;
        width: 25%;
        float: left;
      }
      #footer_column3 {
        margin-top: 200px;
        width: 25%;
        float: left;
      }
      #footer_column4 {
        margin-top: 200px;
        width: 25%;
        float: left;
      }
      <div id="footer">
        <div id="right_triangle"></div>
        <div id="footer_column1">Hello</div>
        <div id="footer_column2">Hello</div>
        <div id="footer_column3">Hello</div>
        <div id="footer_column4">Hello</div>
      </div>


    Notes:

    • Using CSS transform for achieving the triangle in this question would be tough because it will require specific angle calculations for both skew and rotate (depending on which one is used) and hence not recommended.
    • Gradients could have been a good option for this one but unfortunately they get rough and jagged edges at very high dimensions and hence not recommended.
    • If you can change your overall approach, I'd recommend using SVG to create the triangle. It is not that SVG offers any great advantage for this particular shape but it is generally more useful to start learning and using SVG for shapes as it helps in creating a lot of complex ones with ease. Below is a snippet using SVG.

      #footer {
        position: relative;
      }
      #right_triangle {
        position: absolute;
        width: 2000px;
        height: 300px;
        z-index: -1;
      }
      #right_triangle path {
        fill: green;
      }
      #footer_column1 {
        margin-top: 200px;
        width: 25%;
        float: left;
      }
      #footer_column2 {
        margin-top: 200px;
        width: 25%;
        float: left;
      }
      #footer_column3 {
        margin-top: 200px;
        width: 25%;
        float: left;
      }
      #footer_column4 {
        margin-top: 200px;
        width: 25%;
        float: left;
      }
      <div id="footer">
        <svg id="right_triangle" viewBox='0 0 2000 300'>
          <path d='M0,0 2000,300 0,300z' />
        </svg>
        <div id="footer_column1">Hello</div>
        <div id="footer_column2">Hello</div>
        <div id="footer_column3">Hello</div>
        <div id="footer_column4">Hello</div>
      </div>