3

I've already asked once how to create a hexagonal shape in pure html/css. With a little help I found a solution that works just fine in chrome and safari, but neither firefox nor IE support the clip-path property.

The problems as I've already stated in the last question are a few:

  1. I can't use SVG (unless there is a possibility with and <img>-element instead of an <image>-element)
  2. I can't use the image as background-image through CSS
  3. Creating a hexagonal shape with borders ain't no help as I wouldn't be able to add an image inside
  4. The image will be loaded in an <img>-tag
  5. The image can either have no background or be a normal picture as in the example shown
  6. The hexagon should be standing on a side not on an edge

Many have asked a similar question - some could resolve it with svg, some didn't need the border, others didn't have a picture -, yet I couldn't find something that would work with my requirements.

body {
  background: orange;
}

.hex {
  display: inline-block;
  position: relative;
  width: 120px;
  height: 103.92px; /* width * 0.866 */
  background: red;
  box-sizing: border-box;
  -webkit-clip-path: polygon(0% 50%, 25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%);
  -moz-clip-path: polygon(0% 50%, 25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%);
}

.hex-background {
  position: absolute;
  background-color: orange; /*color of the main-background*/
  top: 2px; /* equal to border thickness */
  left: 2px; /* equal to border thickness */
  width: 116px; /* container height - (border thickness * 2) */
  height: 99.92px; /* container height - (border thickness * 2) */
  -webkit-clip-path: polygon(0% 50%, 25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%);
  -moz-clip-path: polygon(0% 50%, 25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%);
}

.hex img {
  position: absolute;
  width: 116px; /* container height - (border thickness * 2) */
  height: 99.92px; /* container height - (border thickness * 2) */
  -webkit-clip-path: polygon(0% 50%, 25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%);
  -moz-clip-path: polygon(0% 50%, 25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%);
}
<div class="hex">
  <div class="hex-background">
    <img src="https://img.clipartfest.com/5e18aeec4df9d62fe5cb5e198e4c56c8_locked-padlock-lock-icon-lock-and-key-clipart-transparent-background_420-420.png">
  </div>
</div>

I've prepared the code as it works in chrome here. As you can see I can create the hexagonal shape, have a border and load an image even with transparent background into it.

Can anyone help me make this cross-browser-compatible? Is this even possible with the requirements I have? May there be a possibility to achieve this with either javascript or jquery?

As always any help would be highly appreciated.

EDIT

It seems that this is almost impossible.

I have an idea in mind which I'm not sure is possible:

Is it possible to get the source (eg. "lalala/lala.png") from an img-element src through and exchange that img-element with the construct needed for the svg-approach with jquery or javascript?

provided:

<img src="lalala/lala.png">

in js:

get src /* result = "lalala/lala.png" */
delete <img src="lalala/lala.png">
put <svg width="a" height="b">
        <image xlink:href="lalala/lala.png" width="a" height="b" />
    </svg>
    where <img scr="lalala/lala.png> has been

NOTE

I've edited the requirements in the list above.

Why are there so many requirements? Well, the problem is that the image that will be displayed inside the hexagon is being provided by a backend where the user can upload images (which will most likely be either in .jpg or .png format). The backend will provide these images in the html-construct as follows:

<img src="somepath/examplepic.png" alt="something"> 

Especially this part has made it way more difficult than I first had thought. Many solutions to this problem included the css-style

background-image: url("somepath/examplepic.png");

which doesn't work as the backend will provide the picture as stated above. Inline-styling is forbidden by my boss.

The svg-approach doesn't work either because if you want an image that is cut to a shape you have to use

<image xlink:href="lalala/lala.png" width="a" height="b" />

inside the <svg>-element which doesn't work either because it's not an <img>-element.

So you see these requirements aren't being made by me because I want to make it complicated but due to the environment I'm working with and in.

Community
  • 1
  • 1
Kathara
  • 1,226
  • 1
  • 12
  • 36
  • I don't believe this is possible given the restrictions you've stated – Rory McCrossan Apr 28 '17 at 07:55
  • I've got the same impression by what I have read so far... – Kathara Apr 28 '17 at 07:56
  • I'd suggest that SVG would be the most appropriate for this, and there are several fallbacks for older browsers, see [this](https://css-tricks.com/a-complete-guide-to-svg-fallbacks) for some more details – Rory McCrossan Apr 28 '17 at 07:58
  • I would love to use the SVG-approach but I can't. The restrictions aren't really made by me, but rather by my boss and the backend we're using... Maybe though I can find a way of using SVG with an img-tag. Thanks for the provided link I'll read through it. – Kathara Apr 28 '17 at 08:01
  • it would be good to know what is the constraint behind "no SVG". e.g. can a data-uri work? keep it simple I Interpret here as "if it is an image, make it an image", but again, it's not mentioned what is the dependency – vv01f Apr 28 '17 at 08:18
  • @vv01f the problem is that our backend would load the wanted image only in an img-tag. So far (with using an image in png-format) I've only found the solution of loading the image through and -tag (eg: ) - which is not the same. And the images that are provided by the backend will either be png- or jpg-images. – Kathara Apr 28 '17 at 08:32
  • @vv01f what would a solution with data-uri look like? I've never used it before and I'm quite new to programming... I've just read the following: https://en.wikipedia.org/wiki/Data_URI_scheme but I think that wouldn't work including my requirements...? – Kathara Apr 28 '17 at 08:34
  • just create an svg, minimize it and make it compatible with css `url()`, that could be set as e.g. background-image (which leads to the question what hinders you from using that one?). many use font-awesome these days, a good to circumvent fonts is just the svg data; look at the symbols/logos [here](https://fsfw-dresden.de/theme/css/fsfw.css) for an example. – vv01f Apr 28 '17 at 08:39
  • @vv01f that results in the problem of not being able to load the image as background-image to css... – Kathara Apr 28 '17 at 08:40
  • the svg could be in a block element positioned (z-index) over your image… and you did not name the constraint other than "dont user x" (always tell why…) – vv01f Apr 28 '17 at 08:41
  • @vv01f sorry, maybe I just haven't made my problem clear: The backend we use will load the image that should be inside the hexagon into an img-tag. It's not possible to load it as a background-image into css and neither into an image-tag as I have found in the svg-approaches so far. That's why there are these constraints. Also in the question I've asked before my reasons are stated already. That's why I linked it in the first place. – Kathara Apr 28 '17 at 08:46
  • @vv01f could you maybe create a fiddle or codepen to show your solution with svg? It doesn't have to be inside a hexagon (quite the complex shape..) but maybe inside a circle which has a border as well? – Kathara Apr 28 '17 at 08:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/142893/discussion-between-vv01f-and-kathara). – vv01f Apr 28 '17 at 09:57

2 Answers2

1

Although it probably still does not fulfill all constrains (I still think it is unclear where exactly they apply… as I do not know the system in question), as the OP asked for demonstration, here we go:

  • I think only the contained image is constrained
  • I assume the shape might be static on the site or in CSS
  • then we just use positioning to stack things on each other

div.inline{
  display:inline-block;
  width:100px;
  height:100px;
  position: relative;
}
#image{
  background-image:url('data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20standalone%3D%22no%22%3F%3E%0A%3Csvg%20width%3D%22100%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20height%3D%22100%22%3E%0A%3Ccircle%20r%3D%2240%22%20stroke%3D%22red%22%20cy%3D%2250%22%20cx%3D%2250%22%20fill%3D%22transparent%22/%3E%0A%3C/svg%3E%0A');
}
#imagebase64{
  background-image:url('data:image/svg+xml;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHdpZHRoPSIxMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgaGVpZ2h0PSIxMDAiPg0KPGNpcmNsZSByPSI0MCIgc3Ryb2tlPSJyZWQiIGN5PSI1MCIgY3g9IjUwIiBmaWxsPSJ0cmFuc3BhcmVudCIvPg0KPC9zdmc+');
}
.relative{
  position: absolute;
  top:0;
  left:0;
}
<!doctype html>
<html><head><title>How to include SVG demo: inline, css, data-url …</title></head><body>

  <div class="inline" id="image">
    <span class="relative" style="top:30%;left:1ex;font-size:20px;">&nbsp;data-url<br>CSS:SVG</span>
  </div>
  <div class="inline" id="imagebase64">
    <span class="relative" style="top:30%;left:1ex;font-size:20px;">&nbsp;data-url<br>CSS:B64</span>
  </div>
  <div class="inline">
    <span class="relative" style="top:30%;left:1ex;font-size:20px;">&nbsp;inline SVG/XML</span>
    <svg height="100" width="100">
      <circle cx="50" cy="50" r="40" stroke="red" stroke-width="1" fill="transparent" />
    </svg>
  </div>

<!-- did not work without version etc. here -->
  <div class="inline">
    <img src="data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20standalone%3D%22no%22%3F%3E%0A%3Csvg%20width%3D%22100%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20height%3D%22100%22%3E%0A%3Ccircle%20r%3D%2240%22%20stroke%3D%22red%22%20cy%3D%2250%22%20cx%3D%2250%22%20fill%3D%22transparent%22/%3E%0A%3C/svg%3E%0A" width="100" height="100" />
    <span class="relative" style="top:30%;left:1ex;font-size:20px;">&nbsp;data-url<br>IMG/SVG<br></span>
  </div>

<div class="clear"></div>

  <div class="inline"><!-- 1st layer -->
    <img src="https://img.clipartfest.com/5e18aeec4df9d62fe5cb5e198e4c56c8_locked-padlock-lock-icon-lock-and-key-clipart-transparent-background_420-420.png" width="100" height="100" />
    <div class="relative"><!-- 2nd layer on top -->
      <svg height="100" width="100">
        <circle cx="50" cy="50" r="49" stroke="red" stroke-width="3" fill="transparent" />
      </svg>
    </div>
  </div>

<!-- final symbol with SVG hexagon -->
<div class="inline">
  <img src="https://img.clipartfest.com/5e18aeec4df9d62fe5cb5e198e4c56c8_locked-padlock-lock-icon-lock-and-key-clipart-transparent-background_420-420.png" width="100" height="100" />
  <div class="relative">
    <!-- viewBox does the scaling -->
    <svg id="color-fill" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100" height="100" viewBox="0 0 300 300" xmlns:xlink="http://www.w3.org/1999/xlink">
      <polygon class="hex" points="299,150 225,280 75,280 1,150 75,20 225,20" stroke="red" stroke-width="9" fill="transparent"></polygon>
    </svg>
  </div>
</div>

</body></html>
  • different approaches of svg inline, as data url inline, as data url in css only (could be inline via style attribute) and with base64 (I wouldnt recommend any longer for svg but for png/jpg/gif etc.)
  • also the final example svg on top of the image to have the desired border shape.

Tools/Links

vv01f
  • 362
  • 1
  • 4
  • 21
1

I have found this solution in the web, im not the autor (the author is Geoffrey Crofte in Codepen), but I simplified a bit and it should work, maybe it can help you getting your solution:

    .hexa, .hexa div {
      margin: 0 auto;
      transform-origin: 50% 50%;
      overflow: hidden;
      width: 300px;
      height: 300px;
    }
    .hexa {
      width: 325px;
      height: 230px;
    }
    .hexa div {
      width: 100%;
      height: 100%;
    }
    .hexa {
      transform: rotate(120deg);
    }
    .hex1 {
      transform: rotate(-60deg);
    }
    .hex2 {
      transform: rotate(-60deg);
    }
    <div class="part">
      <h2>Hexagon</h2>
        <div class="hexa">
          <div class="hex1">
            <div class="hex2">
              <img src="http://nexceris.com/wp-content/uploads/2014/04/bokeh-cover-bg.jpg" alt="" width="320" height="313" />
            </div>
          </div>
        </div>
    </div>

Working fiddle: https://jsfiddle.net/9znph3sb/

vv01f
  • 362
  • 1
  • 4
  • 21
Diego N.
  • 562
  • 3
  • 10
  • thanks. I've seen this solution already but it doesn't have the border around the hexagon. Sadly all solutions I've seen and found so far are always missing a tiny bit of my requirements. And if clip-path would be cross-browser-compatible I wouldn't even have a problem anymore... – Kathara Apr 28 '17 at 11:46
  • mh, I like the solution, it is neat. @Diego can you add 3 shorter rotated boxes forming the border ("top and bottom" or "left and right" borders only)? then this is it I guess. – vv01f Apr 28 '17 at 11:49
  • I'm starting to think about leaving the border out of the requirements... it would simplyfy things.... only problem with leaving it out is when the pictrue doesn't have a background you won't see the shape... – Kathara Apr 28 '17 at 12:16
  • If we have large size image like 418px x 418px shape are distorted how we set – Anmol Ratan Mohla Jul 12 '17 at 10:15
  • @AnmolRatanMohla I've tested it with images far greather than this size and i had no problem, could you put and example? – Diego N. Jul 12 '17 at 11:53
  • @Diego I've used your solution in the end not requiring a background anymore I created a shape with a border only and .png-images without background. Luckily my client decided to use some kind of icons which don't need a background. Thanks again for your help. – Kathara Nov 28 '17 at 14:29