@bebranded/bb-contents 1.0.111 → 1.0.113

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bb-contents.js +120 -85
  2. package/package.json +1 -1
package/bb-contents.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * BeBranded Contents
3
3
  * Contenus additionnels français pour Webflow
4
- * @version 1.0.111
4
+ * @version 1.0.113
5
5
  * @author BeBranded
6
6
  * @license MIT
7
7
  * @website https://www.bebranded.xyz
@@ -32,11 +32,11 @@
32
32
  window._bbContentsInitialized = true;
33
33
 
34
34
  // Log de démarrage simple (une seule fois)
35
- console.log('bb-contents | v1.0.111');
35
+ console.log('bb-contents | v1.0.113');
36
36
 
37
37
  // Configuration
38
38
  const config = {
39
- version: '1.0.111',
39
+ version: '1.0.113',
40
40
  debug: false, // Debug désactivé pour rendu propre
41
41
  prefix: 'bb-', // utilisé pour générer les sélecteurs (data-bb-*)
42
42
  youtubeEndpoint: null, // URL du worker YouTube (à définir par l'utilisateur)
@@ -391,13 +391,17 @@
391
391
  const totalImages = images.length;
392
392
 
393
393
 
394
- // OPTIMISATION: Charger les images sans forcer les dimensions
394
+ // OPTIMISATION: Charger les images et appliquer les styles SVG AVANT le clonage
395
+ // pour éviter les reflows qui causent la saccade de l'animation
395
396
  images.forEach(img => {
396
397
  if (img.dataset.src && !img.src) {
397
398
  img.src = img.dataset.src;
398
399
  img.loading = 'eager';
399
400
  }
400
401
 
402
+ // Détecter si c'est un SVG (par l'extension du src ou le type)
403
+ const isSVG = img.src && (img.src.toLowerCase().endsWith('.svg') || img.src.includes('data:image/svg+xml'));
404
+
401
405
  // OPTIMISATION: Préserver les styles CSS existants (object-fit, etc.)
402
406
  const originalObjectFit = img.style.objectFit || getComputedStyle(img).objectFit;
403
407
  const originalObjectPosition = img.style.objectPosition || getComputedStyle(img).objectPosition;
@@ -405,20 +409,77 @@
405
409
  const originalHeight = img.style.height;
406
410
 
407
411
  img.onload = () => {
408
- // OPTIMISATION: Restaurer les styles CSS après chargement
409
- if (originalObjectFit && originalObjectFit !== 'none') {
410
- img.style.objectFit = originalObjectFit;
411
- }
412
- if (originalObjectPosition && originalObjectPosition !== 'initial') {
413
- img.style.objectPosition = originalObjectPosition;
414
- }
415
-
416
- // OPTIMISATION: Préserver les dimensions naturelles des images
417
- if (!originalWidth || originalWidth === '') {
418
- img.style.width = 'auto';
419
- }
420
- if (!originalHeight || originalHeight === '') {
421
- img.style.height = 'auto';
412
+ // SOLUTION MOBILE SAFARI : Pour les SVG sur mobile Safari, approche différente
413
+ if (isSVG && isMobile && isSafari) {
414
+ // SUR SAFARI MOBILE : Ne PAS utiliser object-fit qui cause du flou
415
+ // Utiliser des dimensions fixes et laisser le SVG se dimensionner naturellement
416
+ img.style.objectFit = 'none';
417
+ img.style.objectPosition = 'center';
418
+
419
+ // Forcer les dimensions du conteneur parent pour contraindre le SVG
420
+ const parent = img.parentElement;
421
+ if (parent) {
422
+ // S'assurer que le parent a des dimensions fixes
423
+ const parentComputed = getComputedStyle(parent);
424
+ if (!parentComputed.width || parentComputed.width === 'auto') {
425
+ parent.style.width = '100%';
426
+ }
427
+ if (!parentComputed.height || parentComputed.height === 'auto') {
428
+ parent.style.height = '100%';
429
+ }
430
+
431
+ parent.style.display = 'flex';
432
+ parent.style.alignItems = 'center';
433
+ parent.style.justifyContent = 'center';
434
+ parent.style.overflow = 'hidden';
435
+ parent.style.boxSizing = 'border-box';
436
+
437
+ // Forcer le SVG à prendre la taille du parent sans object-fit
438
+ img.style.width = '100%';
439
+ img.style.height = '100%';
440
+ img.style.maxWidth = '100%';
441
+ img.style.maxHeight = '100%';
442
+ img.style.boxSizing = 'border-box';
443
+ }
444
+
445
+ // Améliorer le rendu des SVG sans object-fit
446
+ img.style.imageRendering = 'crisp-edges';
447
+ img.style.webkitBackfaceVisibility = 'hidden';
448
+ img.style.backfaceVisibility = 'hidden';
449
+ } else if (isSVG && isMobile) {
450
+ // Pour Chrome mobile, utiliser contain normalement
451
+ img.style.objectFit = 'contain';
452
+ img.style.objectPosition = 'center';
453
+ img.style.maxWidth = '100%';
454
+ img.style.maxHeight = '100%';
455
+ img.style.width = '100%';
456
+ img.style.height = '100%';
457
+ img.style.boxSizing = 'border-box';
458
+
459
+ const parent = img.parentElement;
460
+ if (parent) {
461
+ parent.style.display = 'flex';
462
+ parent.style.alignItems = 'center';
463
+ parent.style.justifyContent = 'center';
464
+ parent.style.overflow = 'hidden';
465
+ parent.style.boxSizing = 'border-box';
466
+ }
467
+ } else {
468
+ // OPTIMISATION: Restaurer les styles CSS après chargement pour les non-SVG
469
+ if (originalObjectFit && originalObjectFit !== 'none') {
470
+ img.style.objectFit = originalObjectFit;
471
+ }
472
+ if (originalObjectPosition && originalObjectPosition !== 'initial') {
473
+ img.style.objectPosition = originalObjectPosition;
474
+ }
475
+
476
+ // OPTIMISATION: Préserver les dimensions naturelles des images
477
+ if (!originalWidth || originalWidth === '') {
478
+ img.style.width = 'auto';
479
+ }
480
+ if (!originalHeight || originalHeight === '') {
481
+ img.style.height = 'auto';
482
+ }
422
483
  }
423
484
 
424
485
  imagesLoaded++;
@@ -430,6 +491,8 @@
430
491
 
431
492
  // SOLUTION SAFARI MOBILE SIMPLE : Attendre plus longtemps
432
493
  const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
494
+ // Détecter spécifiquement Safari (pas Chrome mobile)
495
+ const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent) || /iPhone|iPad|iPod/.test(navigator.userAgent);
433
496
 
434
497
  // Timeout plus long sur mobile pour laisser le temps aux images de se charger
435
498
  const maxWaitTime = isMobile ? 5000 : 3000; // 5 secondes sur mobile
@@ -471,63 +534,9 @@
471
534
  });
472
535
  }
473
536
 
474
- // CORRECTION: Appliquer les styles CSS aux images dans les copies également
475
- // pour éviter les images floues ou mal cadrées
476
- const allImages = scrollContainer.querySelectorAll('img');
477
- allImages.forEach(img => {
478
- // Détecter si c'est un SVG (par l'extension du src ou le type)
479
- const isSVG = img.src && (img.src.toLowerCase().endsWith('.svg') || img.src.includes('data:image/svg+xml'));
480
-
481
- // SOLUTION MOBILE SAFARI : Pour les SVG sur mobile, éviter object-fit qui cause du flou
482
- if (isSVG && isMobile) {
483
- // Sur mobile, utiliser contain pour éviter le débordement, mais avec optimisations anti-flou
484
- img.style.objectFit = 'contain';
485
- img.style.objectPosition = 'center';
486
-
487
- // Ajouter des contraintes pour empêcher le débordement
488
- img.style.maxWidth = '100%';
489
- img.style.maxHeight = '100%';
490
- img.style.width = '100%';
491
- img.style.height = '100%';
492
-
493
- // Forcer le GPU rendering
494
- img.style.webkitTransform = 'translate3d(0, 0, 0)';
495
- img.style.transform = 'translate3d(0, 0, 0)';
496
-
497
- // Améliorer le rendu des SVG
498
- img.style.imageRendering = 'crisp-edges';
499
-
500
- // S'assurer que le conteneur parent permet au SVG de s'afficher correctement
501
- // et empêche le débordement avec overflow hidden
502
- const parent = img.parentElement;
503
- if (parent) {
504
- parent.style.display = 'flex';
505
- parent.style.alignItems = 'center';
506
- parent.style.justifyContent = 'center';
507
- parent.style.overflow = 'hidden'; // Empêcher le débordement
508
- }
509
- } else {
510
- // Pour les images non-SVG ou sur desktop, appliquer les styles normaux
511
- // Vérifier si l'image a déjà des styles inline
512
- if (!img.style.objectFit) {
513
- const computedStyle = getComputedStyle(img);
514
- const objectFit = computedStyle.objectFit;
515
- const objectPosition = computedStyle.objectPosition;
516
-
517
- // Appliquer object-fit si défini dans le CSS
518
- if (objectFit && objectFit !== 'none' && objectFit !== 'fill') {
519
- img.style.objectFit = objectFit;
520
- }
521
- // Appliquer object-position si défini dans le CSS
522
- if (objectPosition && objectPosition !== 'initial' && objectPosition !== '50% 50%') {
523
- img.style.objectPosition = objectPosition;
524
- }
525
- }
526
- }
527
-
528
- // Forcer un reflow pour stabiliser le rendu
529
- void img.offsetHeight;
530
- });
537
+ // Les styles sont maintenant appliqués AVANT le clonage (dans img.onload)
538
+ // Cela évite les reflows qui causaient la saccade de l'animation
539
+ // Les copies héritent automatiquement des styles des images originales
531
540
 
532
541
  // Vérifier que les images ont une taille visible
533
542
  let imagesWithSize = 0;
@@ -559,6 +568,13 @@
559
568
  const step = (parseFloat(speed) * (isVertical ? 1.5 : 0.8)) / 60;
560
569
  let isPaused = false;
561
570
 
571
+ // OPTIMISATION SAFARI MOBILE : Ajouter will-change pour améliorer la fluidité
572
+ if (isSafari && isMobile) {
573
+ scrollContainer.style.willChange = 'transform';
574
+ scrollContainer.style.webkitBackfaceVisibility = 'hidden';
575
+ scrollContainer.style.backfaceVisibility = 'hidden';
576
+ }
577
+
562
578
  // Ajuster la taille du conteneur
563
579
  if (isVertical && !useAutoHeight) {
564
580
  scrollContainer.style.height = totalSize + 'px';
@@ -579,27 +595,35 @@
579
595
  ? `translate3d(0, ${currentPosition}px, 0)`
580
596
  : `translate3d(${currentPosition}px, 0, 0)`;
581
597
  scrollContainer.style.transform = initialTransform;
598
+
599
+ // OPTIMISATION SAFARI MOBILE : Forcer un reflow avant de démarrer l'animation
600
+ if (isSafari && isMobile) {
601
+ void scrollContainer.offsetHeight;
602
+ }
582
603
 
583
- // Fonction d'animation Safari avec debug des resets
604
+ // Fonction d'animation Safari optimisée
584
605
  let frameCount = 0;
585
- const animate = () => {
606
+ let lastTime = performance.now();
607
+ const animate = (currentTime) => {
586
608
  if (!isPaused) {
587
609
  frameCount++;
588
610
 
611
+ // OPTIMISATION SAFARI MOBILE : Utiliser le temps réel pour une animation plus fluide
612
+ const deltaTime = isSafari && isMobile ? (currentTime - lastTime) / 16.67 : 1;
613
+ lastTime = currentTime;
614
+
589
615
  if (direction === (isVertical ? 'bottom' : 'right')) {
590
- currentPosition += step;
616
+ currentPosition += step * deltaTime;
591
617
  if (currentPosition >= 0) {
592
618
  currentPosition = -(finalContentSize + gapSize);
593
619
  }
594
620
  } else {
595
- currentPosition -= step;
621
+ currentPosition -= step * deltaTime;
596
622
  if (currentPosition <= -(2 * (finalContentSize + gapSize))) {
597
623
  currentPosition = -(finalContentSize + gapSize);
598
624
  }
599
625
  }
600
626
 
601
- // Animation continue
602
-
603
627
  // ARRONDI pour éviter les erreurs de précision JavaScript
604
628
  currentPosition = Math.round(currentPosition * 100) / 100;
605
629
 
@@ -612,10 +636,21 @@
612
636
  requestAnimationFrame(animate);
613
637
  };
614
638
 
615
- // Démarrer l'animation avec un petit délai pour Safari
616
- setTimeout(() => {
617
- animate();
618
- }, 50);
639
+ // Démarrer l'animation avec un délai adapté pour Safari
640
+ if (isSafari && isMobile) {
641
+ // Safari mobile : attendre un peu plus pour que tout soit prêt
642
+ requestAnimationFrame(() => {
643
+ requestAnimationFrame(() => {
644
+ lastTime = performance.now();
645
+ animate(lastTime);
646
+ });
647
+ });
648
+ } else {
649
+ setTimeout(() => {
650
+ lastTime = performance.now();
651
+ animate(lastTime);
652
+ }, 50);
653
+ }
619
654
 
620
655
  // Pause au survol pour Safari
621
656
  if (element.getAttribute('bb-marquee-pause') === 'true') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bebranded/bb-contents",
3
- "version": "1.0.111",
3
+ "version": "1.0.113",
4
4
  "description": "Contenus additionnels français pour Webflow",
5
5
  "main": "bb-contents.js",
6
6
  "scripts": {