Transformation CSS avec redimensionnement de l'élément

, j'ai trouvé ceci: largeur/hauteur après transformation

Et plusieurs autres, mais rien n'est pas tout à fait ce que je cherche. Ce que je veux, c'est mettre à l'échelle quelque chose à 50% de sa taille (avec une belle transition animée bien sûr) et que la mise en page se réajuste à la nouvelle taille (visuelle) de l'élément. Ce qui semble se produire par défaut, c'est que l'élément conserve toujours sa taille d'origine dans la structure de mise en page, et est simplement dessiné avec les transformations associées.

Fondamentalement, je veux que l'utilisateur clique sur un bloc de texte( ou un autre contenu), puis redimensionne ce texte à 50% (ou autre) de sa taille et le colle dans un panneau ci-dessous pour indiquer qu'il a été sélectionné. Je ne veux pas 50% d'espaces autour de l'élément après l'avoir déplacé.

J'ai essayé de re-régler la hauteur / largeur, mais cela fait que l'élément iself subit une nouvelle mise en page, puis l'échelle est appliquée à la nouvelle mise en page et cela me laisse toujours 50% d'espace après tout terminer. Mon code spécifique à mozilla (pour plus de simplicité) ressemble à ceci:

<script type="text/javascript">
 function zap(e) {

  var height = e.parentNode.offsetHeight/2 + 'px';
  var width = e.parentNode.offsetWidth/2 + 'px';
  e.parentNode.style.MozTransform='scale(0.0)'; 
  e.parentNode.addEventListener(
    'transitionend', 
    function() { 
      var selectionsArea = document.getElementById("selected");
      selectionsArea.appendChild(e.parentNode);
      e.parentNode.style.MozTransform='scale(0.5,0.5)'; 
      e.parentNode.style.display = 'inline-block';
      e.parentNode.style.height = height;
      e.parentNode.style.width = width;
    },
    true) 
}
</script>

J'espère vraiment que je n'ai pas à jouer avec des marges négatives ou un positionnement relatif pour y parvenir...

Edit: depuis que j'ai écrit ceci, j'ai trouvé une question très similaire Sans commentaires ni réponses. Il diffère légèrement car je ne me soucie pas qu'il s'agisse d'une solution spécifique à html5, je soupçonne que la solution n'existe pas ou se trouve dans CSS / javascript indépendamment du html niveau.

Scale / zoom un élément DOM et l'espace qu'il occupe en utilisant CSS3 transform scale()

Edit 2: (une autre tentative non fonctionnelle)

J'ai aussi essayé cela, mais l'échelle et les fonctions de traduction semblent interagir d'une manière qui rend la position finale impossible à prédire... et scale before transform ne semble pas être le même que transform then scale. Malheureusement ce n'est pas seulement une question d'ajuster la traduction par le facteur d'échelle ...

function posX(e) {
    return e.offsetLeft + (e.offsetParent ? posX(e.offsetParent) : 0)
}

function posY(e) {
    return e.offsetTop + (e.offsetParent ? posY(e.offsetParent) : 0)
}

function placeThumbNail(e, container, x, y, scale) {
    var contX = posX(container);
    var contY = posY(container);
    var eX = posX(e);
    var eY = posY(e);
    var eW = e.offsetWidth;
    var eH = e.offsetHeight;

    var margin = 10;
    var dx = ((contX - eX) + margin + (x * eW * scale));
    var dy = ((contY - eY) + margin + (y * eH * scale));

    // assumes identical objects     
    var trans = 'translate(' + dx + 'px, ' + dy + 'px) ';
    var scale = 'scale(' + scale + ',' + scale + ') ';
    e.style.MozTransform =  trans + scale ; 
}

Même si cela fonctionnait, ce qui précède nécessiterait toujours que je déplace d'abord l'élément vers le bas de la page avant d'exécuter ce code (pour se débarrasser des espaces), et de plus, je devrais recalculer la transformation sur Re-size... donc, je n'étais pas trop content de cette tentative de commencer de toute façon.

Notez Également que si vous utilisez scale + trans vs trans + scale ci-dessus, le résultat est radicalement différent.

Edit 3: j'ai compris les problèmes de placement... les transformations sont appliqués dans l'ordre spécifié, et scale(0.5,0.5) change essentiellement la taille d'un pixel à la moitié de ce qu'il était à l'origine (faisant probablement allusion à la façon dont ils l'ont implémenté en interne). Si je mets translate is first, traduire un peu moins/plus pour tenir compte du changement de position du coin supérieur gauche causé par l'échelle fera l'affaire, mais Gérer l'emplacement des objets et ajuster les transformations lorsque le dom change de manière raisonnable m'échappe encore. Ce genre de se sent mal parce que je dérive dans le sens d'écrire mon propre gestionnaire de mise en page en javascript juste pour obtenir cet effet.

48
demandé sur Community 2012-06-02 03:25:24

3 réponses

Le problème que j'ai remarqué est que lorsque l'élément évolue, le navigateur change son ratio de pixels, pas la quantité de pixels. L'élément est plus petit mais il ne change pas sa taille de pixel réelle dans DOM. Pour cette raison, Je ne pense pas que la solution CSS seule existe.

Je mets un élément évolutif dans un conteneur qui conserve le même ratio de pixels que le reste des éléments. En utilisant Java Script, je change simplement la taille du conteneur. Tout est toujours basé sur CSS3 transform: scale. Peut-être que le code JS pourrait être plus simple, mais maintenant c'est tout à propos de l'idée (juste une preuve de concept);) jouer avec deux exemples: http://jsfiddle.net/qA5Tb/9/

HTML:

<div class="overall-scalable">
    <div class="scalable" scalex='0.5' scaley='0.5'>
        Nunc et nisi ante. Integer in blandit nisi. Nulla facilisi. Vestibulum vulputate sapien eget mauris elementum sollicitudin. Nullam id lobortis dolor. Nulla vitae nibh vitae sem volutpat pretium. Nunc et nisi ante. Integer in blandit nisi. Nulla facilisi. Vestibulum vulputate sapien eget mauris elementum sollicitudin. Nullam id lobortis dolor. Nulla vitae nibh vitae sem volutpat pretium.
    </div>
</div>

CSS:

.overall-scalable {width: 350px; height: 150px; overflow: hidden; -webkit-transition: all 1s;}
.scalable {color: #666; width: 350px; height: 150px; -webkit-transform-origin: top left; -webkit-transition: all 1s;}

JS:

$('button').click(function() {
    $('.scalable').each(function(){
        rescale($(this));
    })
});

function rescale(elem) {

    var height = parseInt(elem.css('height'));
    var width = parseInt(elem.css('width'));
    var scalex = parseFloat(elem.attr('scalex'));
    var scaley = parseFloat(elem.attr('scaley'));

    if (!elem.hasClass('rescaled')){
        var ratioX = scalex;
        var ratioY = scaley;
    }else{          
        var ratioX = 1;
        var ratioY = 1;
    }

    elem.toggleClass('rescaled');
    elem.css('-webkit-transform', 'scale('+ratioX +', '+ratioY+')');        
    elem.parent().css('width', parseInt(width*ratioX) + 'px');
    elem.parent().css('height', parseInt(height*ratioY) + 'px');
}​
37
répondu Sófka 2013-02-20 01:22:05

J'ai finalement trouvé une solution simple et elle est très similaire à celle d'où j'ai commencé.

J'admets qu'il a fallu de nombreuses tentatives pour comprendre cela (au cours de la dernière année) pour finalement le comprendre. Je cherchais en fait une réponse à cette question. J'ai eu des problèmes avec cela. Quoi qu'il en soit, j'ai commencé à travailler à nouveau et j'ai trouvé une solution simple.

Quoi qu'il en soit, l'astuce consistait à utiliser le bas de la marge avec le script CSS calc.

En outre, vous devez avoir une hauteur absolue déclarée pour l'objet (div). Je ne pense pas que cela fonctionnera avec si la div peut se développer, sinon, après de nombreuses tentatives et heures sur cela, j'ai enfin une solution de travail très simple, propre.

Ainsi, par exemple, height = 300px ( pas 30%, ou pas de hauteur). Je voudrais même définir overflow-y = hidden si vous le pouvez. Si vous voulez que la div se développe (ne pas avoir une hauteur absolue), je crois que vous aurez besoin de JavaScript. Je n'ai pas essayé. Sinon, c' fonctionne correctement dans tous les tests.

Je suis sûr que cela fonctionnera bien avec SASS ou moins puisque vous pouvez déclarer certaines des choses répétées en utilisant des variables dans le CSS. Je n'ai pas essayé encore.

Quelques remarques importantes sur ma solution:

  1. notez que j'utilise la hauteur de l'objet et une méthode CSS calc avec la taille de transformation pour comprendre la marge inférieure.
  2. j'ai codé mon travail pour aider à montrer ce qui se passe.
  3. le wrap div a un rembourrage qui n'est là que pour montrer qu'il fonctionne. Ils sont absolus et cela n'affecte pas l'objet interne.
  4. Si vous construisez une page réactive, comme je le suis, vous pouvez utiliser des requêtes multimédia vs des classes pour obtenir le même effet.
  5. j'utilise transform-origin: 50% 0; ce code a fini par ne pas être aussi important que je le pensais à l'origine. J'utilise la marge inférieure pour résoudre les problèmes que j'avais eu.
  6. dans cet exemple, Je ne fais que centrer la div dans le div parent. Si vous avez besoin de placer le div, c'est un peu plus compliqué, mais une semblable solution. Je n'ai pas le tenter.
  7. Vous pouvez utiliser cette même solution avec jQuery vs CSS. L'idée est la même. Vous recherchez tous les éléments avec la transformation dans la page et ajoutez le CSS au besoin.

J'ai aussi mis en place un Codepen pour tester cela avec et pour partager.

Https://codepen.io/cyansmiles/details/yvGaVP

.box-wrap {
  display: block;
  position: relative;
  box-sizing: border-box;
  width: 100%;
  margin: auto;
  text-align: center;
  margin: 30px 10px;
  padding: 40px;
  background: yellow;
}

.box-wrap:before {
  content: "";
  display: block;
  box-sizing: border-box;
  position: absolute;
  background: rgba(0, 0, 0, 0.5);
  width: calc(100% - 80px);
  height: calc(100% - 80px);
  top: 40px;
  left: 40px;
}

.box {
  display: inline-block;
  box-sizing: border-box;
  position: relative;
  transform-origin: 50% 0;
  width: 300px;
  height: 150px;
  background: red;
}

.box.size-80 {
  transform: scale(0.8);
  margin: 0 auto calc(-150px * (1 - 0.8));
}

.box.size-70 {
  transform: scale(0.7);
  margin: 0 auto calc(-150px * (1 - 0.7));
}

.box.size-60 {
  transform: scale(0.6);
  margin: 0 auto calc(-150px * (1 - 0.6));
}

.box.size-50 {
  transform: scale(0.5);
  margin: 0 auto calc(-150px * (1 - 0.5));
}

//etc
<div class="box-wrap">
  <div class="box">
    <h1>Box at 100%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-80">
    <h1>Box at 80%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-70">
    <h1>Box at 70%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
</div>
1
répondu Nathan Sharfi 2018-02-28 02:33:48

J'ai dû modifier mon code un peu d'en haut.

Il fonctionne maintenant de tous les côtés (pas seulement de haut en bas). Je vois un peu d'édition, je pense que c'est un problème CSS (vous pouvez ajouter un autre pixel au code pour résoudre cela).

Voici le lien CodePen de travail. N'hésitez pas à me faire savoir si vous l'utilisez. Je me sentais bien de comprendre enfin cela.

Https://codepen.io/cyansmiles/pen/bLOqZo

Ps. Je bifurque mon codepen pour ajouter un mobile CSS.

.box-wrap {
  display: block;
  position: relative;
  box-sizing: border-box;
  width: 100%;
  margin: auto;
  text-align: center;
  margin: 30px 10px;
  padding: 40px;
  background: yellow;
}

.box-wrap:before {
  content: "";
  display: block;
  box-sizing: border-box;
  position: absolute;
  background: rgba(0, 0, 0, 0.5);
  width: calc(100% - 80px);
  height: calc(100% - 80px);
  top: 40px;
  left: 40px;
}

.box {
  display: inline-block;
  box-sizing: border-box;
  position: relative;
  transform-origin: 50% 0;
  width: 300px;
  height: 150px;
  background: red;
  color: #fff;
}

.box.size-80 {
  background: red;
  transform: scale(0.8);
  margin: 0 calc((-300px * (1 - 0.8)) / 2) calc(-150px * (1 - 0.8));
}

.box.size-70 {
  background: blue;
  transform: scale(0.7);
  margin: 0 calc((-300px * (1 - 0.7)) / 2) calc(-150px * (1 - 0.7));
}

.box.size-60 {
  background: green;
  transform: scale(0.6);
  margin: 0 calc((-300px * (1 - 0.6)) / 2) calc(-150px * (1 - 0.6));
}

.box.size-50 {
  background: orange;
  transform: scale(0.5);
  margin: 0 calc((-300px * (1 - 0.5)) / 2) calc(-150px * (1 - 0.5));
}

//etc
<div class="box-wrap">
  <h1>This is a bunch of boxes!</h1>
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
  <div class="box size-80">
    <h1>Box at 80%</h1>
  </div>
  <div class="box size-70">
    <h1>Box at 70%</h1>
  </div>
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
  <div class="box size-80">
    <h1>Box at 80%</h1>
  </div>
  <div class="box size-70">
    <h1>Box at 70%</h1>
  </div>
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box">
    <h1>Box at 100%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-80">
    <h1>Box at 80%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-70">
    <h1>Box at 70%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
</div>
0
répondu Nathan Sharfi 2018-02-28 02:33:12