5

I am trying to create a menu that contains right triangles formed together to form a square. This is what I envision:

https://i.ibb.co/h7pLqBt/Sample.png

This is what I hope to achieve:

  • Can be dynamically generated through javascript.
  • Scales to parent
  • Clip an image as background for each triangle (cannot be CSS)
  • Link to a site for each triangle
  • Update background and text color when hovering
  • Support multiple browsers

I have tried several different approaches, but encountered several issues with each one:

  • CSS Hack:
    • Cannot set text to correct location
    • Cannot set borders individually
  • SVG
    <div class="menu-box">
    <svg id="menu" style="border: black solid 1px" width="100" height="100" viewbox="0, 0, 100, 100">
      <polygon class = "top" points='0,0 0,100 100,0'  fill="none" stroke="red"/>
      <text x="-18" y="68" fill="black" transform="rotate(-45)">Item</text>
      <polygon  points='100,0 100,100 0,100'  fill="none" stroke="red" />
        <text x="-18" y="84" fill="black" transform="rotate(-45)">Item</text>
    </svg>
    </div>
  • Canvas
    • Difficult dynamically adjust to parent
  • Clip path:
    • Not supported by most browsers.

I understand this is quite ambitious, but any help would be appreciated. I am also open to other ideas, but these were the ones I found online.

Edit: Switch to a better image

4
  • The closest I ever got was using svg. Here is what I had before I ran into an issue: jsfiddle.net/71xp6r0s. I need to be able to click and alter the text and colors of each triangle individually with CSS but from what I read, you can't do that with css. Commented Sep 8, 2019 at 20:11
  • share this into your question and you can do this with CSS Commented Sep 8, 2019 at 20:12
  • To clarify, you can manipulate individual components of an svg with css? Commented Sep 8, 2019 at 20:59
  • 1
    Note that you can use Stack Snippets to reproduce almost anything jsFiddle can do, here on Stack Overflow. Commented Sep 8, 2019 at 21:17

2 Answers 2

4

Here is a idea using skew transformation:

* {
  box-sizing: border-box;
}

.menu {
  width: 150px;
  border: 1px solid;
  overflow: hidden;
  display: flex;
  justify-content: center;
}

/*maitain ratio*/
.menu:before {
  content: "";
  padding-top: 100%;
}

.menu a {
  position:relative;
  width: 100%;
  flex-shrink: 0;
  border: 3px solid red;
  transform: skew(-45deg);
  overflow:hidden;
  color:#fff;
  font-weight:bold;
  font-size:18px;
}

.menu a:first-child span {
  position: absolute;
  bottom:0;
  left: 50%;
  width: 141%;
  display: block;
  text-align: center;
  transform-origin: 86% 100%;
  transform: translate(-50%) skew(45deg) rotate(-45deg) translateX(86%);
}

.menu a:last-child span {
  position: absolute;
  top:0;
  left: 50%;
  width: 141%;
  display: block;
  text-align: center;
  transform-origin: 14% 0%;
  transform: translateX(-50%) skew(45deg) rotate(-45deg) translateX(-86%);
}

.menu a:before {
  content:"";
  position:absolute;
  top:0;
  left:-50%;
  right:-50%;
  bottom:0;
  background:url(https://picsum.photos/id/1069/500/500) center/cover;
  transform: skew(45deg);
}
.menu a:last-child:before {
  background:url(https://picsum.photos/id/1059/500/500) center/cover;
}

/*Hover */
.menu a:hover {
  color:green;
  border-color:yellow;
}
.menu a:hover:before {
  filter:grayscale(100%);
}
<div class="menu">
  <a href="#"><span>Link 1</span></a>
  <a href="#"><span>Link 2</span></a>
</div>

<div class="menu" style="width:200px">
  <a href="#"><span>Link 1</span></a>
  <a href="#"><span>Link 2</span></a>
</div>

<div class="menu" style="width:250px">
  <a href="#"><span>Link 1</span></a>
  <a href="#"><span>Link 2</span></a>
</div>

You can also specify the image directly in the HTML code

* {
  box-sizing: border-box;
}

.menu {
  width: 150px;
  border: 1px solid;
  overflow: hidden;
  display: flex;
  justify-content: center;
}

/*maitain ratio*/
.menu:before {
  content: "";
  padding-top: 100%;
}

.menu a {
  position:relative;
  width: 100%;
  flex-shrink: 0;
  border: 3px solid red;
  transform: skew(-45deg);
  overflow:hidden;
  color:#fff;
  font-weight:bold;
  font-size:18px;
  background-size:0 0;
}


.menu a:first-child span {
  position: absolute;
  bottom:0;
  left: 50%;
  width: 141%;
  display: block;
  text-align: center;
  transform-origin: 86% 100%;
  transform: translate(-50%) skew(45deg) rotate(-45deg) translateX(86%);
}

.menu a:last-child span {
  position: absolute;
  top:0;
  left: 50%;
  width: 141%;
  display: block;
  text-align: center;
  transform-origin: 14% 0%;
  transform: translateX(-50%) skew(45deg) rotate(-45deg) translateX(-86%);
}


.menu a:before {
  content:"";
  position:absolute;
  top:0;
  left:-50%;
  right:-50%;
  bottom:0;
  background-image:inherit;
  background-position:center;
  background-size:cover;
  transform: skew(45deg);
}

/*Hover */
.menu a:hover {
  color:green;
  border-color:yellow;
}
.menu a:hover:before {
  filter:grayscale(100%);
}
<div class="menu">
  <a href="#" style="background-image:url(https://picsum.photos/id/1069/500/500)"><span>Link 1</span></a>
  <a href="#" style="background-image:url(https://picsum.photos/id/1049/500/500)"><span>Link 2</span></a>
</div>

<div class="menu" style="width:200px">
  <a href="#" style="background-image:url(https://picsum.photos/id/1063/500/500)"><span>Link 1</span></a>
  <a href="#" style="background-image:url(https://picsum.photos/id/1069/500/500)"><span>Link 2</span></a>
</div>

<div class="menu" style="width:250px">
  <a href="#" style="background-image:url(https://picsum.photos/id/109/500/500)"><span>Link 1</span></a>
  <a href="#" style="background-image:url(https://picsum.photos/id/1069/500/500)"><span>Link 2</span></a>
</div>

Sign up to request clarification or add additional context in comments.

1 Comment

Wow, I worked on this for almost two days, and got nowhere. It only took you a couple hours and you got the closest. Thank you very much. Apparently the skew transformation was the key. Unfortunately, I need to use img but using your example as a base. I was able to get it. Thanks again.
1

SVG is always your best bet (based on my experience)

SVG Cannot update coloring when hovering. Closest I got was here: https://jsfiddle.net/71xp6r0s

Fiddle

SVG:

<div class="menu-box">
<svg id="menu" style="border: black solid 1px" width="100" height="100" viewbox="0, 0, 100, 100">
 <defs>
        <pattern id="pattern1" height="100%" width="100%" patternContentUnits="objectBoundingBox">
            <image height="1" width="1" preserveAspectRatio="none" xlink:href="https://media.self.com/photos/5b76faf02efd8652915489f5/4:3/w_752,c_limit/4.jpg" />
        </pattern>

                <pattern id="pattern2" height="100%" width="100%" patternContentUnits="objectBoundingBox">
            <image height="1" width="1" preserveAspectRatio="none" xlink:href="https://images2.minutemediacdn.com/image/upload/c_crop,h_2914,w_5184,x_0,y_271/f_auto,q_auto,w_1100/v1566921972/shape/mentalfloss/598021-gettyimages-965401258.jpg" />
        </pattern>
    </defs>

    <a href="https://www.google.com">
        <polygon fill="url(#pattern1)" id="poly1" class = "top" points='0,0 0,100 100,0'  stroke="red"/>
    </a>

  <text x="-18" y="68" fill="black" transform="rotate(-45)">Item</text>

  <a href="https://www.google.com">
    <polygon fill="url(#pattern2)" id="poly2"  points='100,0 100,100 0,100'  stroke="red" />
  </a>
    <text x="-18" y="84" fill="black" transform="rotate(-45)">Item</text>
</svg>
</div>

CSS:

.menu {
  display: relative;
}

.menu .top {
background-color: black;

}

.menu .item {
  clip-path: polygon("0 0, 0 100%, 100% 100%");
}

#poly1:hover{
  fill:red;
}

#poly2:hover{
  fill:purple
}

2 Comments

you are missing 1) Clip an image as background for each triangle (cannot be CSS) 2) Link to a site for each triangle
I am sure the OP can do this easily in SVG I have just solved the issue that was blocking him/her from proceeding with using SVG. However will modify my answer to also add these changes

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.