css - selectores - Uso del ajuste de objetos en un<div> con elementos secundarios, incluido un<canvas>
selector de hijos css (2)
Creo que una solución CSS pura es un poco exagerada considerando la solución que necesita, y aquí hay una propuesta que utiliza un script que incluye los siguientes pasos:
Encuentre la relación de aspecto para la imagen que mejor se ajuste al espacio disponible para el
canvas
width
actualización para elcanvas
y laflexbox
delflexbox
.Dibuja la imagen ahora en el lienzo.
Tenga en cuenta que, por ejemplo, en el cambio de tamaño de la ventana, he vuelto a cargar el marco. Vea la demostración a continuación para obtener más detalles (se proporcionan más explicaciones en línea):
// Document.ready
$(() => {
putImageOnCanvas();
});
// Window resize event
((() => {
window.addEventListener("resize", resizeThrottler, false);
var resizeTimeout;
function resizeThrottler() {
if (!resizeTimeout) {
resizeTimeout = setTimeout(function() {
resizeTimeout = null;
actualResizeHandler();
}, 66);
}
}
function actualResizeHandler() {
// handle the resize event - reloading page for illustration
window.location.reload();
}
})());
function putImageOnCanvas() {
$(''.outerContainer canvas'').each((index, canvas) => {
const ctx = canvas.getContext(''2d'');
canvas.width = $(canvas).innerWidth();
canvas.height = $(canvas).innerHeight();
const img = new Image;
img.src = ''https://static1.squarespace.com/static/56a1d17905caa7ee9f27e273/t/56a1d56617e4f1177a27178d/1453446712144/Picture7.png'';
img.onload = (() => {
// find the aspect ratio that fits the container
let ratio = Math.min(canvas.width / img.width, canvas.height / img.height);
let centerShift_x = (canvas.width - img.width * ratio) / 2;
let centerShift_y = (canvas.height - img.height * ratio) / 2;
canvas.width -= 2 * centerShift_x;
canvas.height -= 2 * centerShift_y;
// reset the flexbox height and canvas flex-basis (adjusting for the 0.5em border too)
$(''.outerContainer'').css({
''height'': ''calc('' + canvas.height + ''px + 1em)''
});
$(''.outerContainer canvas'').css({
''width'': ''calc('' + canvas.width + ''px)''
});
// draw the image in the canvas now
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width * ratio, img.height * ratio);
});
});
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.outerContainer {
display: flex;
border: 0.5em solid #444;
margin-bottom: 2em;
/*max available flexbox height*/
height: calc(100vh - 2em);
}
.outerContainer canvas {
background: #77a;
/*max available canvas width*/
width: calc(100vw - 4em);
}
.outerContainer .beside {
flex-basis: 3em;
flex-grow: 0;
flex-shrink: 0;
background: #7a7;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outerContainer">
<canvas></canvas>
<div class="beside">
</div>
</div>
EDITAR :
Inicialmente estaba configurando
flex-basis
para elcanvas
, pero Firefox no se estaba comportando bien, así que ahora estoy usandowidth
lugar.El fragmento de código tiene algún problema en el cambio de tamaño de la pantalla (recarga de página) nuevamente en Firefox, por lo que también se ha incluido un violín.
Tengo un contenedor exterior que es variable en tamaño y ancho. Supongamos que dentro de este contenedor, tengo un lienzo que quiero que crezca tanto como pueda mientras mantiene la proporción y no recorta. Para esto, normalmente usaría object-fit: contain
.
Ahora, supongamos que en lugar de solo un lienzo, tengo un lienzo con otro elemento colocado al lado.
HTML:
<div class="outerContainer">
<canvas width="640" height="360"></canvas>
<div class="beside">
</div>
</div>
CSS:
.outerContainer {
display: flex;
border: 0.5em solid #444;
margin-bottom: 2em;
object-fit: contain;
}
.outerContainer canvas {
flex-grow: 1;
background: #77a;
}
/* This element has a fixed width, and should be whatever height the <canvas> is */
.outerContainer .beside {
flex-basis: 3em;
flex-grow: 0;
flex-shrink: 0;
background: #7a7;
}
En este caso, quiero escalar todo el tamaño del contenedor externo, tal como lo hice con el lienzo. El problema es que object-fit
no escala realmente el elemento ... escala su contenido. Esto no parece aplicarse a los elementos de bloque normales, lo que resulta en un caso en el que el lienzo en el interior es potencialmente sesgado si hay suficiente ancho.
Si agrego object-fit: contain
al elemento de canvas
, mantiene la proporción pero aún usa todo el ancho, lo que significa que el elemento .beside
está completamente a la derecha. Esto se visualiza con el fondo morado en el lienzo.
Lo que me gustaría es que outerContainer
se outerContainer
con el contenido del lienzo, de modo que .beside
tener la altura del contenido del lienzo. El .outerContainer
debe estar centrado en el elemento padre, ocupando todo el espacio que pueda sin distorsionar el lienzo. Así, en cualquier escala proporcional:
¿Es esto posible con CSS moderno? ¿O debo usar una solución con script?
Tratar con ejemplos: https://jsfiddle.net/nufx10zc/
No sé si está bien para ti, pero creo que se puede hacer principalmente en CSS si permites un poco más de HTML.
Considere el siguiente html
<div class="outerContainer">
<div class="canvasContainer">
<canvas width="640" height="360"></canvas>
</div>
<div class="beside">
</div>
</div>
Acabo de añadir un poco de div alrededor del lienzo. De esta manera, dejamos que el lienzo maneje sus cosas y usamos el div para las cosas flexibles.
Usando el siguiente css:
* {
box-sizing: border-box;
}
.outerContainer {
display: flex;
border: 0.5em solid #444;
margin-bottom: 2em;
}
.canvasContainer canvas {
width: 100%;
background: #777;
margin-bottom: -4px
}
.canvasContainer {
flex-grow: 1;
background: #77a;
}
/* This element has a fixed width, and should be whatever height the <canvas> is */
.outerContainer .beside {
flex-basis: 3em;
flex-grow: 0;
flex-shrink: 0;
background: #7a7;
}
Disponemos de contenedor de lona que ocupa todo el espacio disponible. Y luego el lienzo se adapta en consecuencia con la escala de la imagen en él. Sin embargo, no sé por qué, había un poco de margen en la parte inferior del lienzo, por lo tanto, el margen negativo en él.
Fiddle: https://jsfiddle.net/L8p6xghb/3/
Como nota al margen, si está buscando usar eso para los subtítulos, hay un elemento html5 para él, como <figure>
y <figcaption>
!