25

How can I achieve the following watermark text ("howbloggerz") with css/html?

enter image description here

Captain Obvious
  • 745
  • 3
  • 17
  • 39
  • 1
    I don't believe this can be done with HTML/CSS only as it requires modifying the actual image (otherwise viewers can save the image without the watermark). Is a server sided solution possible? – Gerrit0 Nov 28 '16 at 20:58
  • 1
    It is not required to modify the actual image. Viewers are allowed to save it without watermark in this case :) – Captain Obvious Nov 28 '16 at 21:19
  • This is exactly what i needed to make it obvious an editing copy is displayed instead of the official one. – Samuel Åslund May 19 '17 at 14:56

7 Answers7

31

This is pretty similar to Daerik's answer, but I wanted to avoid using an extra element, and automate the watermark text generation.

document.querySelectorAll('.watermarked').forEach(function(el) {
  el.dataset.watermark = (el.dataset.watermark + ' ').repeat(300);
});
.watermarked {
  position: relative;
  overflow: hidden;
}

.watermarked img {
  width: 100%;
}

.watermarked::before {
  position: absolute;
  top: -75%;
  left: -75%;
  
  display: block;
  width: 150%;
  height: 150%;
  
  transform: rotate(-45deg);
  content: attr(data-watermark);
  
  opacity: 0.7;
  line-height: 3em;
  letter-spacing: 2px;
  color: #fff;
}
<div class="watermarked" data-watermark="howbloggerz">
  <img src="http://www.w3schools.com/css/img_fjords.jpg">
</div>
Gerrit0
  • 7,955
  • 3
  • 25
  • 32
  • Thanks, this might be even easier :) – Captain Obvious Nov 28 '16 at 22:15
  • 1
    `Array.from()` and `String.prototype.repeat()` were introduced in the same ECMAScript 2015 standard (ES6, or ECMA-262), so I'm curious as to why hesitate to use one and not the other? Otherwise, awesome answer. – Patrick Roberts Aug 13 '17 at 00:52
  • 1
    @PatrickRoberts, good question! This was an oversight on my part. I'd gotten so used to having `Array.from` polyfilled, that it completely slipped my mind that support was essentially identical. I've updated the post to use `String.prototype.repeat`. – Gerrit0 Aug 13 '17 at 00:57
  • 1
    Works great. Though I had to avoid using any `JavaScript` since the OP was asking for `CSS/HTML`. That's why I added my suggestion to use `JavaScript` or `jQuery`. – Daerik Oct 13 '17 at 13:46
  • This did not work for me. I noticed that it also doesn't work in your example when I use "Expand snippet"... no watermark is shown. – WilliamK Sep 25 '22 at 22:48
  • @WilliamK you're probably running some ancient browser. Works on latest Firefox, Edge, Chrome – Gerrit0 Sep 27 '22 at 00:44
  • Tried both Firefox and Firefox Dev. The demo worked ok, but when clicking to "Expand" it did not work. What else can I say? – WilliamK Sep 27 '22 at 04:29
  • @WilliamK sounds like a bug with SO's snippet thing to me. Possibly the expand is re-rendering the html without running the JS again? Not sure. – Gerrit0 Sep 27 '22 at 22:50
25

I'm now using svg as a background image. Plain CSS:

body {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='100px' width='100px'><text transform='translate(20, 100) rotate(-45)' fill='rgb(245,45,45)' font-size='20'>watermark</text></svg>");
}
<body style="width:100%;height:100%"></body>

Javascript to set the background:

function watermark(text) {
  var body = document.getElementsByTagName('body')[0];
  var bg = "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='100px' width='100px'>" +
    "<text transform='translate(20, 100) rotate(-45)' fill='rgb(245,45,45)' font-size='20' >" + text + "</text></svg>\")";
  body.style.backgroundImage = bg
}

//for this test
var input = document.getElementById('a');
watermark(input.value);
input.addEventListener('input', function(evt) {
  watermark(this.value);
});
<body style="width:100%;height:100%">
  <input id="a" value="change me" />
</body>
estani
  • 24,254
  • 2
  • 93
  • 76
20

Set the size of your container and float your text using absolute positioning while transforming your text with rotate.

#watermark {
  height: 450px;
  width: 600px;
  position: relative;
  overflow: hidden;
}
#watermark img {
  max-width: 100%;
}
#watermark p {
  position: absolute;
  top: 0;
  left: 0;
  color: #fff;
  font-size: 18px;
  pointer-events: none;
  -webkit-transform: rotate(-45deg);
  -moz-transform: rotate(-45deg);
}
<div id="watermark">
  <img src="http://www.topchinatravel.com/pic/city/dalian/attraction/people-square-1.jpg">
  <p>This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark. This is a watermark.</p>
</div>

Note: For repeating text, I would suggest using either JavaScript or jQuery.

Daerik
  • 4,167
  • 2
  • 20
  • 33
2

If it is only to lay a text over the image, here is another possible css option with drop-shadow and a pseudo (text-shadow works too)

.watermarked:after {/* draw the watermark at screen*/
  color: rgba(0, 0, 0, 0.4);
  content: 'watermarked watermarked watermarked';
  word-spacing: 3em;
  transform: rotate(-60deg);
  filter: 
  drop-shadow(2em 3em  #000) 
  drop-shadow(4em 6em  #000) 
  drop-shadow(8em 12em #000) 
  drop-shadow(-15em -24em #000)
  ;
}

/* makeup */
.watermarked {
  width: max-content;
  border: solid;
  display: grid;
  overflow: hidden;
}

img,
.watermarked:after {
  grid-row: 1;
  grid-column: 1;
  margin: auto;
}
<div class="watermarked" data-watermark="howbloggerz">
  <img src="http://www.w3schools.com/css/img_fjords.jpg">
</div>
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
1

     Array.from(document.querySelectorAll('.watermarked')).forEach(function(el) {
        el.dataset.watermark = (el.dataset.watermark + ' ').repeat(300);
    });
.watermarked::before {
    position: fixed;
    top: -75%;
    left: -75%;

    display: block;
    width: 300%;
    height: 300%;

    transform: rotate(-45deg);
    content: attr(data-watermark);

    font-size: 30px;
    opacity: 0.75;
    line-height: 4em;
    letter-spacing: 2px;
    color: #cccccc;
}
<html>
<head>
<title>
Form and Watermarks
</title>
</head>
<body>

<h1>Form Demo</h1>
<form method="post">
    First Name: <input name="first" type="text" /><br>
    Last name: <input name="last" type="text" />
    <br />
    <input name="Submit" type="submit" value="submit" />
</form>

<div class='watermarked' data-watermark='watermark..' ></div>

</body>
</html>

It works great but not with html form. The form elements become disabled. Check this out.

Baki
  • 11
  • 1
  • This issue is also happening with hyperlinks etc... I got the problem fixed by adding pointer-events: none; – Baki Jan 08 '21 at 02:25
0
CSS:-
.watermarked::before {
    position: fixed;
    top: -75%;
    left: -75%;

    display: block;
    width: 300%;
    height: 300%;

    transform: rotate(-45deg);
    content: attr(data-watermark);

    font-size: 30px;
    opacity: 0.15;
    line-height: 4em;
    letter-spacing: 2px;
    color: #ff0523;
    z-index:-1;
}

HTML:-
<div class="watermarked" data-watermark="Watermark.."></div>

SCRIPT:-

<script>        
Array.from(document.querySelectorAll('.watermarked')).forEach(function(el) {
        el.dataset.watermark = (el.dataset.watermark + ' ').repeat(10000);
    });
</script>

watermark position should be as fixed and display with & height should be your screen size. Then watermark will be printed in your whole report or something.

Hashan
  • 164
  • 8
0

document.querySelectorAll('.watermarked').forEach(function(el) {
  el.dataset.watermark = (el.dataset.watermark + ' ').repeat(300);
});
.watermarked {
  position: relative;
  overflow: hidden;
}

.watermarked img {
  width: 100%;
}

.watermarked::before {
  position: absolute;
  top: -75%;
  left: -75%;
  
  display: block;
  width: 150%;
  height: 150%;
  
  transform: rotate(-45deg);
  content: attr(data-watermark);
  
  opacity: 0.7;
  line-height: 3em;
  letter-spacing: 2px;
  color: #fff;
}
<div class="watermarked" data-watermark="howbloggerz">
  <img src="http://www.w3schools.com/css/img_fjords.jpg">
</div>

     Array.from(document.querySelectorAll('.watermarked')).forEach(function(el) {
        el.dataset.watermark = (el.dataset.watermark + ' ').repeat(300);
    });
.watermarked::before {
    position: fixed;
    top: -75%;
    left: -75%;

    display: block;
    width: 300%;
    height: 300%;

    transform: rotate(-45deg);
    content: attr(data-watermark);

    font-size: 30px;
    opacity: 0.75;
    line-height: 4em;
    letter-spacing: 2px;
    color: #cccccc;
}
<html>
<head>
<title>
Form and Watermarks
</title>
</head>
<body>

<h1>Form Demo</h1>
<form method="post">
    First Name: <input name="first" type="text" /><br>
    Last name: <input name="last" type="text" />
    <br />
    <input name="Submit" type="submit" value="submit" />
</form>

<div class='watermarked' data-watermark='watermark..' ></div>

</body>
</html>
  • Hi and welcome. Thanks for sharing your code as answer. It is always good to explain a bit via text the code. So the readers get a bit of background. – KargWare Dec 19 '22 at 07:53