<?php
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Extension\SandboxExtension;
use Twig\Markup;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityNotAllowedTagError;
use Twig\Sandbox\SecurityNotAllowedFilterError;
use Twig\Sandbox\SecurityNotAllowedFunctionError;
use Twig\Source;
use Twig\Template;
/* index.twig */
class __TwigTemplate_1288a8c934165619861e7a1b14d9faa4 extends \Eccube\Twig\Template
{
private $source;
private $macros = [];
public function __construct(Environment $env)
{
parent::__construct($env);
$this->source = $this->getSourceContext();
$this->blocks = [
'main' => [$this, 'block_main'],
'stylesheet' => [$this, 'block_stylesheet'],
'javascript' => [$this, 'block_javascript'],
];
}
protected function doGetParent(array $context)
{
// line 1
return "default_frame.twig";
}
protected function doDisplay(array $context, array $blocks = [])
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "index.twig"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "index.twig"));
// line 2
$context["body_class"] = "front_page";
// line 1
$this->parent = $this->loadTemplate("default_frame.twig", "index.twig", 1);
$this->parent->display($context, array_merge($this->blocks, $blocks));
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
}
// line 3
public function block_main($context, array $blocks = [])
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "main"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "main"));
// line 4
echo "<div class=\"mycarousel-wrapper\">
<div class=\"mycarousel-slider\">
";
// line 7
echo " ";
$context["pc_images"] = [0 => "main-visual.jpg", 1 => "main-visual.jpg", 2 => "main-visual.jpg"];
// line 12
echo "
";
// line 14
echo " ";
$context["sp_images"] = [0 => "sp-topImages.jpg", 1 => "sp-topImages.jpg", 2 => "sp-topImages.jpg"];
// line 19
echo "
";
// line 21
echo " ";
$context["display_images"] = [0 => 0, 1 => 1, 2 => 2];
// line 22
echo "
";
// line 23
$context['_parent'] = $context;
$context['_seq'] = twig_ensure_traversable((isset($context["display_images"]) || array_key_exists("display_images", $context) ? $context["display_images"] : (function () { throw new RuntimeError('Variable "display_images" does not exist.', 23, $this->source); })()));
foreach ($context['_seq'] as $context["_key"] => $context["index"]) {
// line 24
echo " <div class=\"mycarousel-slide\">
<img class=\"desktop-image\" src=\"";
// line 25
echo twig_escape_filter($this->env, $this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl(("/html/user_data/ContentImg/" . twig_get_attribute($this->env, $this->source, (isset($context["pc_images"]) || array_key_exists("pc_images", $context) ? $context["pc_images"] : (function () { throw new RuntimeError('Variable "pc_images" does not exist.', 25, $this->source); })()), $context["index"], [], "array", false, false, false, 25))), "html", null, true);
echo "\" alt=\"スライド画像\">
<img class=\"mobile-image\" src=\"";
// line 26
echo twig_escape_filter($this->env, $this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl(("/html/user_data/ContentImg/" . twig_get_attribute($this->env, $this->source, (isset($context["sp_images"]) || array_key_exists("sp_images", $context) ? $context["sp_images"] : (function () { throw new RuntimeError('Variable "sp_images" does not exist.', 26, $this->source); })()), $context["index"], [], "array", false, false, false, 26))), "html", null, true);
echo "\" alt=\"スライド画像\">
</div>
";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_iterated'], $context['_key'], $context['index'], $context['_parent'], $context['loop']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 29
echo " </div>
</div>
";
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
}
// line 32
public function block_stylesheet($context, array $blocks = [])
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "stylesheet"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "stylesheet"));
// line 33
echo "<style>
/* slickのデフォルト黒丸(before擬似要素)を無効化 */
.mycarousel-slider .slick-dots li button::before {
display: none;
content: '';
}
.slick-dots li {
position:unset;
display: inline-block;
width: 20px;
height: 20px;
margin: 0 5px;
padding: 0;
cursor: pointer;
}
.mycarousel-slider .slick-dots li {
width: 10px;
height: 10px;
}
.mycarousel-slider .slick-dots li button {
width: 100%;
height: 100%;
padding: 0;
border: none;
border-radius: 50%;
background-color: #ccc;
opacity: 0.7;
transition: all 0.3s ease;
font-size: 0;
cursor: pointer;
}
.mycarousel-slider .slick-dots li.slick-active button {
background-color: #b8860b;
transform: scale(1.3);
opacity: 1;
}
/* フルワイドの外枠 */
.mycarousel-wrapper {
width: 100vw;
max-width: none;
margin-left: calc(-50vw + 50%);
margin-right: calc(-50vw + 50%);
overflow: hidden;
padding: 0;
/* 初期化時のちらつき防止 */
visibility: hidden;
}
/* slickのトラック修正 */
.slick-track {
display: flex !important;
align-items: center;
}
.slick-slide {
padding: 0 !important;
margin: 0 !important;
}
/* スライド本体(動的高さ対応) */
.mycarousel-slide {
box-sizing: border-box;
padding: 0 !important;
margin: 0 !important;
position: relative;
transition: all 0.5s ease;
overflow: hidden;
/* 高さは動的に設定される */
height: 60vh; /* 初期値:JavaScript で調整される */
}
/* 画像の基本スタイル */
.desktop-image,
.mobile-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: all 0.5s ease;
/* object-fit は JavaScript で動的に調整 */
object-fit: contain;
}
/* デスクトップ時のスタイル(768pxより大きい) */
@media (min-width: 769px) {
.desktop-image {
display: block !important;
}
.mobile-image {
display: none !important;
}
}
/* モバイル時のスタイル(768px以下) */
@media (max-width: 768px) {
.mycarousel-wrapper {
width: 100vw;
margin-left: calc(-50vw + 50%);
margin-right: calc(-50vw + 50%);
}
.mycarousel-slide {
width: 100vw !important;
height: auto !important;
padding: 0 !important;
margin: 0 !important;
opacity: 1 !important;
filter: none !important;
}
.desktop-image {
display: none !important;
}
.mobile-image {
display: block !important;
position: relative !important;
width: 100% !important;
height: auto !important;
object-fit: contain !important;
filter: brightness(1) contrast(1) !important;
}
}
/* 左右の画像を暗くするエフェクト(デスクトップのみ) */
@media (min-width: 769px) {
.mycarousel-slide.side-slide {
opacity: 0.6;
}
.mycarousel-slide.side-slide .desktop-image {
filter: brightness(0.7) contrast(0.9);
}
.mycarousel-slide.center-slide {
opacity: 1;
}
.mycarousel-slide.center-slide .desktop-image {
filter: brightness(1) contrast(1);
}
.mycarousel-slide.side-slide:hover {
opacity: 0.8;
transform: scale(1.02);
}
.mycarousel-slide.side-slide:hover .desktop-image {
filter: brightness(0.85) contrast(0.95);
}
}
/* 動的高さ調整用のユーティリティクラス */
.dynamic-fit-contain {
object-fit: contain;
}
.dynamic-fit-cover {
object-fit: cover;
}
</style>
";
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
}
// line 190
public function block_javascript($context, array $blocks = [])
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascript"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascript"));
// line 191
echo "<script>
\$(function() {
// 動的レスポンシブ設定
const RESPONSIVE_CONFIG = {
desktop: {
targetAspectRatio: 16/9,
minHeight: '30vh',
maxHeight: '60vh',
marginThreshold: 0.15
},
mobile: {
targetAspectRatio: 4/3,
minHeight: '35vh',
maxHeight: '85vh',
marginThreshold: 0.12
}
};
let isInitialized = false;
let currentImages = [];
// 画面幅に応じた動的centerPadding計算
function calculateCenterPadding() {
const windowWidth = \$(window).width();
let padding;
// 画面幅に応じてcenterPaddingを計算(調整可能な閾値)
if (windowWidth <= 768) {
// モバイル: 余白なし
padding = '0';
} else if (windowWidth <= 1024) {
// タブレット: 小さめの余白
padding = '8vw';
} else if (windowWidth <= 1200) {
// 小型デスクトップ: 中程度の余白
padding = '12vw';
}else if (windowWidth <= 1440) {
// 小型デスクトップ: 中程度の余白
padding = '15vw';
} else if (windowWidth <= 1920) {
// 標準デスクトップ: やや大きめの余白
padding = '20vw';
} else {
// 大型ディスプレイ: 最大余白を制限
padding = '25vw';
}
return padding;
}
// centerPaddingを動的に更新する関数
function updateCenterPadding() {
const newPadding = calculateCenterPadding();
const windowWidth = \$(window).width();
// モバイルはcenterMode自体を無効にする
const centerModeEnabled = windowWidth > 768;
if (\$('.mycarousel-slider').hasClass('slick-initialized')) {
\$('.mycarousel-slider').slick('slickSetOption', 'centerMode', centerModeEnabled, false);
\$('.mycarousel-slider').slick('slickSetOption', 'centerPadding', newPadding, true);
}
}
// 現在のデバイスに応じた画像を取得
function getCurrentImages() {
const isMobile = \$(window).width() <= 768;
return isMobile ? \$('.mobile-image') : \$('.desktop-image');
}
// 画像プリロード関数
function preloadImages() {
return new Promise((resolve) => {
const images = getCurrentImages();
let loadedCount = 0;
const totalImages = images.length;
if (totalImages === 0) {
resolve();
return;
}
images.each(function() {
const img = this;
if (img.complete && img.naturalWidth > 0) {
loadedCount++;
if (loadedCount >= totalImages) {
resolve();
}
} else {
\$(img).on('load error', function() {
loadedCount++;
if (loadedCount >= totalImages) {
resolve();
}
});
// 強制的に再読み込みをトリガー(キャッシュ対策)
if (!img.src) {
img.src = img.getAttribute('src');
}
}
});
});
}
// スライダー初期化(動的centerPadding対応版)
function initializeSlider() {
if (\$('.mycarousel-slider').hasClass('slick-initialized')) {
\$('.mycarousel-slider').slick('unslick');
}
const initialPadding = calculateCenterPadding();
const windowWidth = \$(window).width();
const centerModeEnabled = windowWidth > 768;
\$('.mycarousel-slider').slick({
centerMode: centerModeEnabled,
centerPadding: initialPadding,
slidesToShow: 1,
autoplay: false, // 初期化時は自動再生を無効にして安定性を確保
autoplaySpeed: 5000,
arrows: true,
dots: true,
adaptiveHeight: false,
fade: false,
speed: 300
// responsive設定は削除(動的制御に切り替え)
});
// スライド変更時にクラスを更新
\$('.mycarousel-slider').on('afterChange', function(event, slick, currentSlide) {
updateSlideClasses();
});
}
// 動的な表示最適化メイン関数
function optimizeCarouselDisplay() {
const isMobile = \$(window).width() <= 768;
const config = isMobile ? RESPONSIVE_CONFIG.mobile : RESPONSIVE_CONFIG.desktop;
const \$currentImages = getCurrentImages();
if (\$currentImages.length === 0) return;
// モバイル時は簡単な設定にする
if (isMobile) {
// モバイル時:width 100vw、height auto
\$('.mycarousel-slide').css({
'height': 'auto',
'width': '100vw'
});
\$currentImages.css({
'width': '100%',
'height': 'auto',
'object-fit': 'contain',
'position': 'relative'
});
// 初期化完了後に自動再生を開始
if (isInitialized && \$('.mycarousel-slider').slick('slickGetOption', 'autoplay') === false) {
\$('.mycarousel-slider').slick('slickSetOption', 'autoplay', true, true);
}
return;
}
const \$firstImage = \$currentImages.filter(':visible').first();
if (\$firstImage.length === 0 || !\$firstImage[0].complete || !\$firstImage[0].naturalWidth) {
return;
}
const imageWidth = \$firstImage[0].naturalWidth;
const imageHeight = \$firstImage[0].naturalHeight;
const imageAspectRatio = imageWidth / imageHeight;
const containerWidth = \$('.mycarousel-wrapper').width();
const containerAspectRatio = config.targetAspectRatio;
const maxRenderWidth = Math.min(imageWidth, containerWidth);
const maxRenderHeight = maxRenderWidth / imageAspectRatio;
const viewportMinHeightPx = parseFloat(config.minHeight) * \$(window).height() / 100;
const viewportMaxHeightPx = parseFloat(config.maxHeight) * \$(window).height() / 100;
let optimalHeight;
let objectFitMode = 'contain';
const aspectRatioDiff = Math.abs(imageAspectRatio - containerAspectRatio) / containerAspectRatio;
if (maxRenderHeight <= viewportMaxHeightPx && maxRenderHeight >= viewportMinHeightPx) {
optimalHeight = maxRenderHeight;
} else if (maxRenderHeight > viewportMaxHeightPx) {
if (aspectRatioDiff <= config.marginThreshold) {
optimalHeight = viewportMaxHeightPx;
} else {
optimalHeight = Math.min(containerWidth / imageAspectRatio, viewportMaxHeightPx);
}
} else {
if (maxRenderHeight < viewportMinHeightPx) {
const scaleUpLimit = Math.min(2.0, viewportMinHeightPx / maxRenderHeight);
if (scaleUpLimit <= 1.5) {
optimalHeight = viewportMinHeightPx;
} else {
optimalHeight = maxRenderHeight;
}
} else {
optimalHeight = maxRenderHeight;
}
}
// 最終的な制限適用
optimalHeight = Math.max(viewportMinHeightPx, Math.min(viewportMaxHeightPx, optimalHeight));
// 画像の品質を考慮したobject-fit調整
const renderScale = optimalHeight / maxRenderHeight;
if (renderScale > 1.2) {
objectFitMode = 'contain';
} else {
objectFitMode = 'contain';
}
// スタイル適用(デスクトップのみ)
\$('.mycarousel-slide').css('height', optimalHeight + 'px');
\$currentImages.css({
'object-fit': objectFitMode,
'image-rendering': renderScale > 1.1 ? 'smooth' : 'auto'
});
// 初期化完了後に自動再生を開始
if (isInitialized && \$('.mycarousel-slider').slick('slickGetOption', 'autoplay') === false) {
\$('.mycarousel-slider').slick('slickSetOption', 'autoplay', true, true);
}
}
// スライドのクラスを更新する関数
function updateSlideClasses() {
\$('.mycarousel-slide').removeClass('center-slide side-slide');
if (\$(window).width() > 768) {
\$('.slick-center .mycarousel-slide').addClass('center-slide');
\$('.slick-slide:not(.slick-center) .mycarousel-slide').addClass('side-slide');
} else {
\$('.mycarousel-slide').addClass('center-slide');
}
}
async function initialize() {
try {
// カルーセルを一時的に非表示にしてちらつき防止
\$('.mycarousel-wrapper').css('visibility', 'hidden');
await preloadImages();
initializeSlider();
optimizeCarouselDisplay();
updateSlideClasses();
isInitialized = true;
// 6. 少し待ってから表示(slickの初期化完了を確実にする)
setTimeout(() => {
\$('.mycarousel-wrapper').css('visibility', 'visible');
// 初期化後にもう一度表示を最適化
optimizeCarouselDisplay();
updateSlideClasses();
}, 50);
console.log('Carousel initialized successfully');
} catch (error) {
console.error('Carousel initialization failed:', error);
// エラー時も表示を戻す
\$('.mycarousel-wrapper').css('visibility', 'visible');
}
}
let resizeTimer;
\$(window).on('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(async () => {
// centerPaddingを動的に更新
updateCenterPadding();
// デバイス切り替わり時は再初期化
const newImages = getCurrentImages();
const imagesSwitched = !currentImages.length ||
newImages.length !== currentImages.length ||
newImages[0] !== currentImages[0];
if (imagesSwitched) {
currentImages = newImages;
await preloadImages();
}
optimizeCarouselDisplay();
updateSlideClasses();
}, 200);
});
\$(document).ready(function() {
currentImages = getCurrentImages();
initialize();
});
\$(window).on('load', function() {
if (!isInitialized) {
initialize();
}
});
});
</script>
";
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
}
public function getTemplateName()
{
return "index.twig";
}
public function isTraitable()
{
return false;
}
public function getDebugInfo()
{
return array ( 313 => 191, 303 => 190, 137 => 33, 127 => 32, 115 => 29, 106 => 26, 102 => 25, 99 => 24, 95 => 23, 92 => 22, 89 => 21, 86 => 19, 83 => 14, 80 => 12, 77 => 7, 73 => 4, 63 => 3, 52 => 1, 50 => 2, 37 => 1,);
}
public function getSourceContext()
{
return new Source("{% extends 'default_frame.twig' %}
{% set body_class = 'front_page' %}
{% block main %}
<div class=\"mycarousel-wrapper\">
<div class=\"mycarousel-slider\">
{# PC用画像リスト main-visual.jpg #}
{% set pc_images = [
'main-visual.jpg',
'main-visual.jpg',
'main-visual.jpg'
] %}
{# SP用画像リスト sp-topImages.jpg #}
{% set sp_images = [
'sp-topImages.jpg',
'sp-topImages.jpg',
'sp-topImages.jpg'
] %}
{# 実際に表示する画像を選択(0から始まるインデックス番号で指定) #}
{% set display_images = [0,1,2] %}
{% for index in display_images %}
<div class=\"mycarousel-slide\">
<img class=\"desktop-image\" src=\"{{ asset('/html/user_data/ContentImg/' ~ pc_images[index]) }}\" alt=\"スライド画像\">
<img class=\"mobile-image\" src=\"{{ asset('/html/user_data/ContentImg/' ~ sp_images[index]) }}\" alt=\"スライド画像\">
</div>
{% endfor %}
</div>
</div>
{% endblock %}
{% block stylesheet %}
<style>
/* slickのデフォルト黒丸(before擬似要素)を無効化 */
.mycarousel-slider .slick-dots li button::before {
display: none;
content: '';
}
.slick-dots li {
position:unset;
display: inline-block;
width: 20px;
height: 20px;
margin: 0 5px;
padding: 0;
cursor: pointer;
}
.mycarousel-slider .slick-dots li {
width: 10px;
height: 10px;
}
.mycarousel-slider .slick-dots li button {
width: 100%;
height: 100%;
padding: 0;
border: none;
border-radius: 50%;
background-color: #ccc;
opacity: 0.7;
transition: all 0.3s ease;
font-size: 0;
cursor: pointer;
}
.mycarousel-slider .slick-dots li.slick-active button {
background-color: #b8860b;
transform: scale(1.3);
opacity: 1;
}
/* フルワイドの外枠 */
.mycarousel-wrapper {
width: 100vw;
max-width: none;
margin-left: calc(-50vw + 50%);
margin-right: calc(-50vw + 50%);
overflow: hidden;
padding: 0;
/* 初期化時のちらつき防止 */
visibility: hidden;
}
/* slickのトラック修正 */
.slick-track {
display: flex !important;
align-items: center;
}
.slick-slide {
padding: 0 !important;
margin: 0 !important;
}
/* スライド本体(動的高さ対応) */
.mycarousel-slide {
box-sizing: border-box;
padding: 0 !important;
margin: 0 !important;
position: relative;
transition: all 0.5s ease;
overflow: hidden;
/* 高さは動的に設定される */
height: 60vh; /* 初期値:JavaScript で調整される */
}
/* 画像の基本スタイル */
.desktop-image,
.mobile-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: all 0.5s ease;
/* object-fit は JavaScript で動的に調整 */
object-fit: contain;
}
/* デスクトップ時のスタイル(768pxより大きい) */
@media (min-width: 769px) {
.desktop-image {
display: block !important;
}
.mobile-image {
display: none !important;
}
}
/* モバイル時のスタイル(768px以下) */
@media (max-width: 768px) {
.mycarousel-wrapper {
width: 100vw;
margin-left: calc(-50vw + 50%);
margin-right: calc(-50vw + 50%);
}
.mycarousel-slide {
width: 100vw !important;
height: auto !important;
padding: 0 !important;
margin: 0 !important;
opacity: 1 !important;
filter: none !important;
}
.desktop-image {
display: none !important;
}
.mobile-image {
display: block !important;
position: relative !important;
width: 100% !important;
height: auto !important;
object-fit: contain !important;
filter: brightness(1) contrast(1) !important;
}
}
/* 左右の画像を暗くするエフェクト(デスクトップのみ) */
@media (min-width: 769px) {
.mycarousel-slide.side-slide {
opacity: 0.6;
}
.mycarousel-slide.side-slide .desktop-image {
filter: brightness(0.7) contrast(0.9);
}
.mycarousel-slide.center-slide {
opacity: 1;
}
.mycarousel-slide.center-slide .desktop-image {
filter: brightness(1) contrast(1);
}
.mycarousel-slide.side-slide:hover {
opacity: 0.8;
transform: scale(1.02);
}
.mycarousel-slide.side-slide:hover .desktop-image {
filter: brightness(0.85) contrast(0.95);
}
}
/* 動的高さ調整用のユーティリティクラス */
.dynamic-fit-contain {
object-fit: contain;
}
.dynamic-fit-cover {
object-fit: cover;
}
</style>
{% endblock %}
{% block javascript %}
<script>
\$(function() {
// 動的レスポンシブ設定
const RESPONSIVE_CONFIG = {
desktop: {
targetAspectRatio: 16/9,
minHeight: '30vh',
maxHeight: '60vh',
marginThreshold: 0.15
},
mobile: {
targetAspectRatio: 4/3,
minHeight: '35vh',
maxHeight: '85vh',
marginThreshold: 0.12
}
};
let isInitialized = false;
let currentImages = [];
// 画面幅に応じた動的centerPadding計算
function calculateCenterPadding() {
const windowWidth = \$(window).width();
let padding;
// 画面幅に応じてcenterPaddingを計算(調整可能な閾値)
if (windowWidth <= 768) {
// モバイル: 余白なし
padding = '0';
} else if (windowWidth <= 1024) {
// タブレット: 小さめの余白
padding = '8vw';
} else if (windowWidth <= 1200) {
// 小型デスクトップ: 中程度の余白
padding = '12vw';
}else if (windowWidth <= 1440) {
// 小型デスクトップ: 中程度の余白
padding = '15vw';
} else if (windowWidth <= 1920) {
// 標準デスクトップ: やや大きめの余白
padding = '20vw';
} else {
// 大型ディスプレイ: 最大余白を制限
padding = '25vw';
}
return padding;
}
// centerPaddingを動的に更新する関数
function updateCenterPadding() {
const newPadding = calculateCenterPadding();
const windowWidth = \$(window).width();
// モバイルはcenterMode自体を無効にする
const centerModeEnabled = windowWidth > 768;
if (\$('.mycarousel-slider').hasClass('slick-initialized')) {
\$('.mycarousel-slider').slick('slickSetOption', 'centerMode', centerModeEnabled, false);
\$('.mycarousel-slider').slick('slickSetOption', 'centerPadding', newPadding, true);
}
}
// 現在のデバイスに応じた画像を取得
function getCurrentImages() {
const isMobile = \$(window).width() <= 768;
return isMobile ? \$('.mobile-image') : \$('.desktop-image');
}
// 画像プリロード関数
function preloadImages() {
return new Promise((resolve) => {
const images = getCurrentImages();
let loadedCount = 0;
const totalImages = images.length;
if (totalImages === 0) {
resolve();
return;
}
images.each(function() {
const img = this;
if (img.complete && img.naturalWidth > 0) {
loadedCount++;
if (loadedCount >= totalImages) {
resolve();
}
} else {
\$(img).on('load error', function() {
loadedCount++;
if (loadedCount >= totalImages) {
resolve();
}
});
// 強制的に再読み込みをトリガー(キャッシュ対策)
if (!img.src) {
img.src = img.getAttribute('src');
}
}
});
});
}
// スライダー初期化(動的centerPadding対応版)
function initializeSlider() {
if (\$('.mycarousel-slider').hasClass('slick-initialized')) {
\$('.mycarousel-slider').slick('unslick');
}
const initialPadding = calculateCenterPadding();
const windowWidth = \$(window).width();
const centerModeEnabled = windowWidth > 768;
\$('.mycarousel-slider').slick({
centerMode: centerModeEnabled,
centerPadding: initialPadding,
slidesToShow: 1,
autoplay: false, // 初期化時は自動再生を無効にして安定性を確保
autoplaySpeed: 5000,
arrows: true,
dots: true,
adaptiveHeight: false,
fade: false,
speed: 300
// responsive設定は削除(動的制御に切り替え)
});
// スライド変更時にクラスを更新
\$('.mycarousel-slider').on('afterChange', function(event, slick, currentSlide) {
updateSlideClasses();
});
}
// 動的な表示最適化メイン関数
function optimizeCarouselDisplay() {
const isMobile = \$(window).width() <= 768;
const config = isMobile ? RESPONSIVE_CONFIG.mobile : RESPONSIVE_CONFIG.desktop;
const \$currentImages = getCurrentImages();
if (\$currentImages.length === 0) return;
// モバイル時は簡単な設定にする
if (isMobile) {
// モバイル時:width 100vw、height auto
\$('.mycarousel-slide').css({
'height': 'auto',
'width': '100vw'
});
\$currentImages.css({
'width': '100%',
'height': 'auto',
'object-fit': 'contain',
'position': 'relative'
});
// 初期化完了後に自動再生を開始
if (isInitialized && \$('.mycarousel-slider').slick('slickGetOption', 'autoplay') === false) {
\$('.mycarousel-slider').slick('slickSetOption', 'autoplay', true, true);
}
return;
}
const \$firstImage = \$currentImages.filter(':visible').first();
if (\$firstImage.length === 0 || !\$firstImage[0].complete || !\$firstImage[0].naturalWidth) {
return;
}
const imageWidth = \$firstImage[0].naturalWidth;
const imageHeight = \$firstImage[0].naturalHeight;
const imageAspectRatio = imageWidth / imageHeight;
const containerWidth = \$('.mycarousel-wrapper').width();
const containerAspectRatio = config.targetAspectRatio;
const maxRenderWidth = Math.min(imageWidth, containerWidth);
const maxRenderHeight = maxRenderWidth / imageAspectRatio;
const viewportMinHeightPx = parseFloat(config.minHeight) * \$(window).height() / 100;
const viewportMaxHeightPx = parseFloat(config.maxHeight) * \$(window).height() / 100;
let optimalHeight;
let objectFitMode = 'contain';
const aspectRatioDiff = Math.abs(imageAspectRatio - containerAspectRatio) / containerAspectRatio;
if (maxRenderHeight <= viewportMaxHeightPx && maxRenderHeight >= viewportMinHeightPx) {
optimalHeight = maxRenderHeight;
} else if (maxRenderHeight > viewportMaxHeightPx) {
if (aspectRatioDiff <= config.marginThreshold) {
optimalHeight = viewportMaxHeightPx;
} else {
optimalHeight = Math.min(containerWidth / imageAspectRatio, viewportMaxHeightPx);
}
} else {
if (maxRenderHeight < viewportMinHeightPx) {
const scaleUpLimit = Math.min(2.0, viewportMinHeightPx / maxRenderHeight);
if (scaleUpLimit <= 1.5) {
optimalHeight = viewportMinHeightPx;
} else {
optimalHeight = maxRenderHeight;
}
} else {
optimalHeight = maxRenderHeight;
}
}
// 最終的な制限適用
optimalHeight = Math.max(viewportMinHeightPx, Math.min(viewportMaxHeightPx, optimalHeight));
// 画像の品質を考慮したobject-fit調整
const renderScale = optimalHeight / maxRenderHeight;
if (renderScale > 1.2) {
objectFitMode = 'contain';
} else {
objectFitMode = 'contain';
}
// スタイル適用(デスクトップのみ)
\$('.mycarousel-slide').css('height', optimalHeight + 'px');
\$currentImages.css({
'object-fit': objectFitMode,
'image-rendering': renderScale > 1.1 ? 'smooth' : 'auto'
});
// 初期化完了後に自動再生を開始
if (isInitialized && \$('.mycarousel-slider').slick('slickGetOption', 'autoplay') === false) {
\$('.mycarousel-slider').slick('slickSetOption', 'autoplay', true, true);
}
}
// スライドのクラスを更新する関数
function updateSlideClasses() {
\$('.mycarousel-slide').removeClass('center-slide side-slide');
if (\$(window).width() > 768) {
\$('.slick-center .mycarousel-slide').addClass('center-slide');
\$('.slick-slide:not(.slick-center) .mycarousel-slide').addClass('side-slide');
} else {
\$('.mycarousel-slide').addClass('center-slide');
}
}
async function initialize() {
try {
// カルーセルを一時的に非表示にしてちらつき防止
\$('.mycarousel-wrapper').css('visibility', 'hidden');
await preloadImages();
initializeSlider();
optimizeCarouselDisplay();
updateSlideClasses();
isInitialized = true;
// 6. 少し待ってから表示(slickの初期化完了を確実にする)
setTimeout(() => {
\$('.mycarousel-wrapper').css('visibility', 'visible');
// 初期化後にもう一度表示を最適化
optimizeCarouselDisplay();
updateSlideClasses();
}, 50);
console.log('Carousel initialized successfully');
} catch (error) {
console.error('Carousel initialization failed:', error);
// エラー時も表示を戻す
\$('.mycarousel-wrapper').css('visibility', 'visible');
}
}
let resizeTimer;
\$(window).on('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(async () => {
// centerPaddingを動的に更新
updateCenterPadding();
// デバイス切り替わり時は再初期化
const newImages = getCurrentImages();
const imagesSwitched = !currentImages.length ||
newImages.length !== currentImages.length ||
newImages[0] !== currentImages[0];
if (imagesSwitched) {
currentImages = newImages;
await preloadImages();
}
optimizeCarouselDisplay();
updateSlideClasses();
}, 200);
});
\$(document).ready(function() {
currentImages = getCurrentImages();
initialize();
});
\$(window).on('load', function() {
if (!isInitialized) {
initialize();
}
});
});
</script>
{% endblock %}", "index.twig", "/home/iseyabread/www/iseya/app/template/default/index.twig");
}
}