46 votes

Comment obtenir un effet de papier déchiré avec des dents de scie aléatoires ?

J'essaie de faire un effet de papier déchiré comme l'image ci-dessous :

enter image description here

avec l'effet de déchirure sur le côté inférieur. J'ai vu ça et j'ai pu réaliser un effet de papier déchiré comme indiqué ci-dessous.

.box {
  width: 300px;
  height: 150px;
  background: darkred;
  position: relative;
  display: inline-block;
}
.box:after {
  position: absolute;
  content: "";
  width: 15px;
  height: 15px;
  transform: rotate(45deg);
  transform-origin: 0% 100%;
  background: darkred;
  left: 0;
  bottom: 0;
  box-shadow: 15px -15px 0 0 darkred, 30px -30px 0 0 darkred, 45px -45px 0 0 darkred, 60px -60px 0 0 darkred, 75px -75px 0 0 darkred, 90px -90px 0 0 darkred, 105px -105px 0 0 darkred, 120px -120px 0 0 darkred, 135px -135px 0 0 darkred, 150px -150px 0 0 darkred, 165px -165px 0 0 darkred, 180px -180px 0 0 darkred, 195px -195px 0 0 darkred;
}

<div class="box"></div>

Mais le problème est que les bords déchirés se ressemblent. Je veux qu'ils soient de tailles différentes avec des formes différentes.

4 votes

Si vous préférez un aspect plus "réaliste", vous pouvez utiliser une image PNG personnalisée et un découpage de l'image en bordure, comme dans cette question : stackoverflow.com/questions/29349151/ utilisez simplement une image avec l'effet sur le bord droit au lieu du haut et du bas comme dans l'exemple de ma réponse. stackoverflow.com/a/31392023/4952851 .

1 votes

Les gens doivent arrêter de prétendre que CSS est un programme de dessin.

50voto

Akshay Points 6324

Cela peut être fait en utilisant svg. J'utilise Snap et jquery pour le faire car cela rend tout beaucoup plus facile.

Les extraits suivants créent des effets aléatoires de papier déchiré.

Note : Prise en charge de l'instantané - IE9 et plus, Safari, Chrome, Firefox et Opera voir les spécifications

Support pour les svg caniuse

$(document).ready(function() {
  var s = Snap('svg');
  var width = $('.content').outerWidth();
  $('.effect').width(width);
  var lastX = 0;
  var pointsArray = [0, 0];
  while (lastX <= width) {
    var randX = Math.floor(Math.random() * 25);
    var randY = Math.floor(Math.random() * 30);
    pointsArray.push(randX + lastX + ' ' + randY);
    lastX = lastX + randX;
  }
  var torn = s.polygon(pointsArray + " " + width + " 0").attr({
    fill: 'orange'
  })
})

.content {
  width: 400px;
  height: 400px;
  background: orange;
  padding: 20px;
}
.effect {
  height: 50px;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div class="torn">
  <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
  <div class="effect">
    <svg width="100%" height="100%"></svg>
  </div>
</div>

Comment cela fonctionne-t-il ?

Tout d'abord, un tableau est créé pour contenir les coordonnées qui sont créées de manière aléatoire par Jquery. Les coordonnées x et y sont créées à l'aide de la fonction Math.random() Avant de les ajouter au tableau, la coordonnée x actuelle est ajoutée à la dernière coordonnée x reçue. Ceci afin de rendre le processus continu.

Changer le 10 dans le randX nous permet d'augmenter ou de diminuer la longueur d'une ligne et de modifier la variable 30 dans le randY permet de modifier la hauteur d'une ligne.

Voici un extrait qui utilise une faible randX

$(document).ready(function() {
  var s = Snap('svg');
  var width = $('.content').outerWidth();
  $('.effect').width(width);
  var lastX = 0;
  var lastY = 0;
  var pointsArray = [0, 0];
  while (lastX <= width) {
    var randX = Math.floor(Math.random() * 2);
    var randY = Math.floor(Math.random() * 30);
    pointsArray.push(randX + lastX + ' ' + randY);
    lastX = lastX + randX;
  }
  var torn = s.polygon(pointsArray + " " + width + " 0").attr({
    fill: 'orange'
  })
})

.content {
  width: 400px;
  height: 400px;
  background: orange;
  padding: 20px;
}
.effect {
  height: 50px;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div class="torn">
  <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
  <div class="effect">
    <svg width="100%" height="100%"></svg>
  </div>
</div>

Vous aimeriez en avoir un avec une bordure ?

Changement polygon à polyline et ajouter stroke

$(document).ready(function() {
  var s = Snap('svg');
  var width = $('.content').outerWidth();
  $('.effect').width(width);
  var lastX = 0;
  var lastY = 0;
  var pointsArray = [0, 0];
  while (lastX <= width) {
    var randX = Math.floor(Math.random() * 20);
    var randY = Math.floor(Math.random() * 30);
    pointsArray.push(randX + lastX + ' ' + randY);
    lastX = lastX + randX;
  }
  var torn = s.polyline(pointsArray + " " + (width - 3) + " 0").attr({
    fill: 'orange',
    'stroke': 'black',
    'stroke-width': 3
  })
})

.torn {
  margin: 50px;
}
.content {
  width: 400px;
  height: 400px;
  background: orange;
  padding: 20px;
  border: 3px solid #000;
  border-bottom: 0;
}
.effect {
  height: 50px;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div class="torn">
  <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
  <div class="effect">
    <svg width="100%" height="100%"></svg>
  </div>
</div>

Vous n'aimez pas les effets déchirés aléatoires ?

Je vous suggère de choisir un bel effet déchiré parmi les effets aléatoires et de copier son html comme je l'ai fait ici.

.torn {
  margin: 50px;
}
.content {
  width: 400px;
  height: 400px;
  background: orange;
  padding: 20px;
}
.effect {
  height: 50px;
}

<div class="torn">
  <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
  <div class="effect" style="width: 440px;">
    <svg width="100%" height="100%">
      <desc>Created with Snap</desc>
      <defs></defs>
      <polygon points="0,0,10 25,20 15,27 21,43 24,51 14,70 9,84 25,88 18,96 11,100 20,113 6,117 5,123 1,136 25,151 29,157 4,166 29,181 2,197 28,212 8,226 8,232 12,240 8,254 16,270 5,279 26,291 5,304 0,307 5,325 26,329 18,347 3,360 5,372 26,382 9,393 21,406 27,411 8,415 4,429 8,441 19 437 0"
      fill="#ffa500"></polygon>
    </svg>
  </div>
</div>

Besoin d'images de fond ?

Ajoutez une image en utilisant snap, définissez ses coordonnées y à -440 (c'est-à-dire la hauteur du contenu.400 si le remplissage est évité) et découpez-la en utilisant le polygone.

$(document).ready(function() {
  var s = Snap('svg');
  var width = $('.content').outerWidth();
  $('.effect').width(width);
  var lastX = 0;
  var lastY = 0;
  var pointsArray = [0, 0];
  while (lastX <= width) {
    var randX = Math.floor(Math.random() * 20);
    var randY = Math.floor(Math.random() * 30);
    pointsArray.push(randX + lastX + ' ' + randY);
    lastX = lastX + randX;
  }
  var img = s.image('https://placeimg.com/440/500/any', 0, -440, 440, 500)
  var torn = s.polygon(pointsArray + " " + (width - 3) + " 0").attr({

  })
  img.attr({
    'clip-path': torn
  })
})

.torn {
  margin: 50px;
}
.content {
  width: 400px;
  height: 400px;
  background: orange;
  padding: 20px;
  background: url('https://placeimg.com/440/500/any');
}
.effect {
  height: 50px;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div class="torn">
  <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
  <div class="effect">
    <svg width="100%" height="100%"></svg>
  </div>
</div>

1 votes

Votre code pour générer les points aléatoires a un bug : il peut déborder. Si lastX est très proche de width puis en ajoutant lastX + randX peut devenir plus grand que width . Vous pouvez très bien voir cet effet dans l'exemple de la bordure.

0 votes

J'ai remarqué que @r0estir0bbe mais comme il déborde, il semble que cela fasse partie de l'effet de coupe donc je n'ai rien fait pour cela.

2 votes

@machineyearning : Je suis tout à fait d'accord avec le fait que la réponse d'Akshay semble bien meilleure, mais juste pour vous faire savoir que les 3 premiers extraits de ma réponse ont des points fixes qui ont été ajoutés arbitrairement. Le dernier extrait produirait le même résultat que dans la réponse d'Akshay si la logique de génération de tableau est réglée pour être exactement la même que celle d'Akshay. C'est juste une question de génération de tableau.

41voto

Harry Points 10265

Utilisation des chemins de coupe :

L'effet de papier déchiré peut également être produit en utilisant clip-path Il est possible de le faire uniquement avec HTML et CSS, mais la version purement CSS ne produirait pas un effet de clip aléatoire comme nous pouvons le faire en utilisant SNAP ou d'autres bibliothèques SVG, mais elle produit un effet de papier déchiré.

Le site inconvénient de l'utilisation de CSS clip-path est que c'est actuellement pris en charge uniquement dans les navigateurs optimisés pour Webkit . Firefox ne prend en charge que le url() et a donc besoin de SVGs en ligne alors qu'il n'a absolument aucun support dans IE. [ Puis-je utiliser ]

.torn-paper{
  height: 300px;
  width: 400px;
  background: tomato;
  -webkit-clip-path: polygon(0% 0%, 0% 97%, 2% 95%, 6% 99%, 12% 88%, 18% 92%, 27% 90%, 31% 97%, 39% 91%, 47% 95%, 60% 83%, 62% 81%, 69% 93%, 72% 96%, 79% 87%, 100% 99%, 100% 0%);
  clip-path: polygon(0% 0%, 0% 97%, 2% 95%, 6% 99%, 12% 88%, 18% 92%, 27% 90%, 31% 97%, 39% 91%, 47% 95%, 60% 83%, 62% 81%, 69% 93%, 72% 96%, 79% 87%, 100% 99%, 100% 0%);  
}

<div class='torn-paper'>Lorem ipsum dolor sit amet</div>

Comme le clip-path est basée sur un pourcentage, elle est par défaut réactive et peut fonctionner lorsque le conteneur div a également une image de fond.

.torn-paper{
  height: 300px;
  width: 400px;
  background: url(http://lorempixel.com/400/300);
  -webkit-clip-path: polygon(0% 0%, 0% 97%, 2% 95%, 6% 99%, 12% 88%, 18% 92%, 27% 90%, 31% 97%, 39% 91%, 47% 95%, 60% 83%, 62% 81%, 69% 93%, 72% 96%, 79% 87%, 100% 99%, 100% 0%);
  clip-path: polygon(0% 0%, 0% 97%, 2% 95%, 6% 99%, 12% 88%, 18% 92%, 27% 90%, 31% 97%, 39% 91%, 47% 95%, 60% 83%, 62% 81%, 69% 93%, 72% 96%, 79% 87%, 100% 99%, 100% 0%);  
}

<div class='torn-paper'>Lorem ipsum dolor sit amet</div>

Si nous voulons vraiment obtenir un effet aléatoire de papier déchiré, nous pouvons définir les coordonnées de l'objet de l'image. polygon clip path en utilisant JS et ensuite l'ajouter comme un style en ligne comme dans le snippet ci-dessous. L'extrait utilise une logique similaire à celle de votre réponse pour remplir le tableau.

var el = document.getElementsByClassName('torn-paper')[0];

var lastX = 0,
  randX, randY, polygonPoints = ["0% 0%"];

randY = Math.floor(Math.random() * 20) + 80;

polygonPoints.push(lastX + '% ' + randY + '%');

while (lastX <= 100) {
  randX = Math.floor(Math.random() * 5);
  randY = Math.floor(Math.random() * 10) + 85;
  polygonPoints.push(randX + lastX + '% ' + randY + '%');
  lastX = lastX + randX;
}
polygonPoints.push("100% 0%");

el.style['-webkit-clip-path'] = 'polygon(' + polygonPoints.join() + ')';
el.style['clip-path'] = 'polygon(' + polygonPoints.join() + ')';

.torn-paper {
  height: 300px;
  width: 400px;
  background: tomato;
}

0
<div class='torn-paper'>Lorem ipsum dolor sit amet</div>

Je n'avais pas fait de ce qui suit ma réponse principale parce que les SVG ont déjà été couverts d'une manière différente dans la réponse d'Akshay, mais l'utilisation de SVG en ligne pour les clip-path fonctionnerait également dans Firefox . IE ne le supporte toujours pas.

var el = document.getElementsByClassName('torn-paper')[0];
var path = document.getElementById('clipper-path');

var lastX = 0,
  randX, randY, polygonPoints = ["0 0"];

randY = (Math.floor(Math.random() * 20) + 80) / 100;

polygonPoints.push(lastX + ' ' + randY + '');

while (lastX <= 1) {
  randX = Math.floor(Math.random() * 5) / 100;
  randY = (Math.floor(Math.random() * 10) + 85) / 100;
  polygonPoints.push(randX + lastX + ' ' + randY + '');
  lastX = lastX + randX;
}
polygonPoints.push("1 0");

path.setAttribute('d', 'M' + polygonPoints.join() + 'z');

.torn-paper {
  height: 300px;
  width: 400px;
  background: tomato;
  -webkit-clip-path: url(#clipper);
  clip-path: url(#clipper);
}

<svg width="0" height="0">
  <defs>
    <clipPath id="clipper" clipPathUnits="objectBoundingBox">
      <path d='M0 0, 1 0, 1 1, 0 1z' id='clipper-path' />
    </clipPath>
  </defs>
</svg>
<div class="torn-paper">Lorem ipsum dolor sit amet</div>

Utilisation de Canvas :

Je sais que vous n'avez pas marqué Canvas, mais si vous cherchez un support pour IE également, l'utilisation de Canvas serait également une bonne option. Canvas est très bien supporté par les navigateurs (comme SVG). Je l'inclus ici juste comme une autre option qui pourrait être utilisée.

L'approche est très similaire à celle expliquée précédemment, car ici aussi nous créons un chemin et nous découpons le canevas en fonction de ce chemin.

Les extraits ci-dessous sont testé dans IE9+, Edge, Firefox, Chrome, Safari et Opera .

var canvas = document.getElementById('torn-canvas');
var ctx = canvas.getContext('2d');
var lastX = 0,
  randX, randY;

ctx.save();
ctx.beginPath();
ctx.moveTo(0, 0);

randY = (Math.floor(Math.random() * 10) + 85) / 100 * canvas.height;
ctx.lineTo(0, randY);

while (lastX <= canvas.width) {
  randX = (Math.floor(Math.random() * 7.5)) / 100 * canvas.width;
  randY = (Math.floor(Math.random() * 10) + 85) / 100 * canvas.height;
  lastX = lastX + randX;
  ctx.lineTo(lastX, randY);
}
ctx.lineTo(canvas.width, 0);
ctx.closePath();
ctx.clip();
ctx.beginPath();
ctx.fillStyle = 'tomato';
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fill();
ctx.restore();

.container {
  position: relative;
  height: 300px;
  width: 400px;
}
#torn-canvas {
  position: absolute;
  z-index: -1;
}

<div class='container'>
  <canvas id='torn-canvas' height='300px' width='300px'></canvas>Lorem ipsum dolor sit amet...</div>

Nous pouvons même ajouter une image comme arrière-plan en dessinant d'abord l'image sur le Canvas, puis en la découpant en forme.

var canvas = document.getElementById('torn-canvas');
var ctx = canvas.getContext('2d');
var lastX = 0,
  randX, randY, img = new Image();

ctx.save();
img.src = 'http://lorempixel.com/400/300/nature/4';
img.onload = function() {
  ctx.drawImage(img, 0, 0);
}
ctx.restore();
ctx.beginPath();
ctx.moveTo(0, 0);

randY = (Math.floor(Math.random() * 10) + 85) / 100 * canvas.height;
ctx.lineTo(0, randY);

while (lastX <= canvas.width) {
  randX = (Math.floor(Math.random() * 5)) / 100 * canvas.width;
  randY = (Math.floor(Math.random() * 10) + 85) / 100 * canvas.height;
  lastX = lastX + randX;
  ctx.lineTo(lastX, randY);
}
ctx.lineTo(canvas.width, 0);
ctx.closePath();
ctx.clip();
ctx.beginPath();
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.restore();

.container {
  position: relative;
  height: 300px;
  width: 400px;
  color: white;
}
#torn-canvas {
  position: absolute;
  z-index: -1;
}

<div class='container'>
  <canvas id='torn-canvas' height='300px' width='300px'></canvas>Lorem ipsum dolor sit amet...</div>

3 votes

Probablement déclassée parce qu'elle n'est pas aussi portable que l'autre réponse.

3 votes

L'autre fonctionne dans IE et Firefox. Il n'y a rien de mal à ajouter la réponse, mais ne vous énervez pas si elle est déclassée parce qu'elle ne fonctionne pas.

3 votes

J'ai déjà ajouté une version qui fonctionne aussi dans Firefox. Je ne veux pas être désagréable, mais je trouve ridicule que les gens décotent une réponse simplement parce que la technologie n'est pas aussi populaire actuellement. Je peux comprendre que vous (pas exactement vous) choisissiez de ne pas voter, mais décoter une réponse qui répond à la question qui ne mentionne aucune contrainte de navigateur est carrément ridicule.

4voto

Tymn Urban Points 151

Je suis sûr que ce post est probablement mort, mais je laisse ce commentaire ici au cas où quelqu'un le trouve utile. J'ai créé un effet en dents de scie avec le CSS suivant :

clip-path: polygon(3% 0, 7% 1%, 11% 0%, 16% 2%, 20% 0, 23% 2%, 28% 2%, 32% 1%, 35% 1%, 39% 3%, 41% 1%, 45% 0%, 47% 2%, 50% 2%, 53% 0, 58% 2%, 60% 2%, 63% 1%, 65% 0%, 67% 2%, 69% 2%, 73% 1%, 76% 1%, 79% 0, 82% 1%, 85% 0, 87% 1%, 89% 0, 92% 1%, 96% 0, 98% 3%, 99% 3%, 99% 6%, 100% 11%, 98% 15%, 100% 21%, 99% 28%, 100% 32%, 99% 35%, 99% 40%, 100% 43%, 99% 48%, 100% 53%, 100% 57%, 99% 60%, 100% 64%, 100% 68%, 99% 72%, 100% 75%, 100% 79%, 99% 83%, 100% 86%, 100% 90%, 99% 94%, 99% 98%, 95% 99%, 92% 99%, 89% 100%, 86% 99%, 83% 100%, 77% 99%, 72% 100%, 66% 98%, 62% 100%, 59% 99%, 54% 99%, 49% 100%, 46% 98%, 43% 100%, 40% 98%, 38% 100%, 35% 99%, 31% 100%, 28% 99%, 25% 99%, 22% 100%, 19% 99%, 16% 100%, 13% 99%, 10% 99%, 7% 100%, 4% 99%, 2% 97%, 1% 97%, 0% 94%, 1% 89%, 0% 84%, 1% 81%, 0 76%, 0 71%, 1% 66%, 0% 64%, 0% 61%, 0% 59%, 1% 54%, 0% 49%, 1% 45%, 0% 40%, 1% 37%, 0% 34%, 1% 29%, 0% 23%, 2% 20%, 1% 17%, 1% 13%, 0 10%, 1% 6%, 1% 3%);

Je suis sûr que cette méthode peut être affinée pour donner un aspect plus convaincant, mais je pense que c'est un excellent moyen de donner une forme grossière à une zone d'image.

0 votes

Bienvenue sur Stack Overflow ! Veuillez prendre le tour et lire le aide pour savoir comment rédiger de bonnes questions et réponses. Votre réponse n'aborde pas la partie aléatoire de la question. C'est-à-dire que le papier sera "déchiré" de la même façon pour chaque élément. Notez que la réponse acceptée utilise une fonction aléatoire dans le code.

0 votes

@CJDennis - Je crois que le PO voulait dire apparemment "aléatoire" par opposition à réellement aléatoire. L'OP voulait une variété de profondeurs de dents de scie par opposition à toutes les dents étant même comme une scie réelle, comme décrit : "Je veux qu'elles soient de différentes tailles et de différentes formes." C'est ce que l'on entend par "aléatoire" et cela peut être accompli sans randomisation réelle. Cette solution uniquement CSS est géniale !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X