Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create Triangle Menu

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
    • Cannot update coloring when hovering. Closest I got was here: https://jsfiddle.net/71xp6r0s
    <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

like image 660
ghost013 Avatar asked Sep 08 '19 18:09

ghost013


2 Answers

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>
like image 166
Temani Afif Avatar answered Oct 17 '22 23:10

Temani Afif


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
}
like image 1
ProllyGeek Avatar answered Oct 17 '22 23:10

ProllyGeek