유저자료실

2025.10.21 21:22

PWA 앱 설치 이후 플로팅 버튼에 대한 수정 코드

  • 토시아 14일 전 2025.10.21 21:22 기타
  • 19
    0

<?php

if (!defined('_GNUBOARD_')) exit;

include_once("./_common.php");

?>

<style type="text/css">

/* 페이지 하단 여백 - 탭바 높이만큼 */

body.pwa-mobile {

padding-bottom: 60px;

}

/* 하단 고정 탭바 스타일 */

.floating-tabbar {

display: none;

position: fixed;

bottom: 0;

left: 0;

right: 0;

height: 60px;

background: rgba(0, 0, 0, 0.4);

backdrop-filter: blur(20px);

-webkit-backdrop-filter: blur(20px);

border-top: 1px solid rgba(255, 255, 255, 0.2);

z-index: 1000;

padding: 0 10px;

box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.2);

transition: background 0.3s ease;

}

/* 밝은 배경용 스타일 */

.floating-tabbar.light-mode {

background: rgba(255, 255, 255, 0.95);

border-top: 1px solid rgba(0, 0, 0, 0.1);

box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.1);

}

.floating-tabbar-container {

display: flex;

align-items: center;

justify-content: space-between;

height: 100%;

width: 100%;

}

/* 히스토리 네비게이션 */

.floating-tabbar-history {

display: flex;

align-items: center;

gap: 8px;

margin-right: 3px;

}

.floating-tabbar-history-btn {

display: flex;

align-items: center;

justify-content: center;

width: 50px;

height: 35px;

cursor: pointer;

transition: all 0.3s ease;

position: relative;

overflow: hidden;

}

.floating-tabbar-history-btn:disabled {

opacity: 0.3;

cursor: not-allowed;

}

.floating-tabbar-history-btn::before {

content: '';

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

background: rgba(255, 255, 255, 0.2);

border-radius: 8px;

opacity: 0;

transition: opacity 0.3s ease;

}

.floating-tabbar.light-mode .floating-tabbar-history-btn::before {

background: rgba(0, 0, 0, 0.1);

}

.floating-tabbar-history-btn:not(:disabled):active::before {

opacity: 1;

}

.floating-tabbar-history-btn:not(:disabled):active {

transform: scale(0.9);

}

.floating-tabbar-history-icon {

width: 24px;

height: 24px;

stroke: rgba(255, 255, 255, 0.9);

transition: all 0.3s ease;

}

.floating-tabbar.light-mode .floating-tabbar-history-icon {

stroke: rgba(0, 0, 0, 0.8);

}

.floating-tabbar-menu {

display: flex;

align-items: center;

flex: 1;

}

.floating-tabbar-menu > div {

flex: 1;

}

.floating-tabbar-item {

display: flex;

flex-direction: column;

align-items: center;

justify-content: center;

gap: 4px;

cursor: pointer;

transition: all 0.3s ease;

padding: 8px 12px;

border-radius: 12px;

user-select: none;

position: relative;

overflow: hidden;

flex: 1;

text-decoration: none;

}

.floating-tabbar-item::before {

content: '';

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

background: rgba(255, 255, 255, 0.2);

border-radius: 12px;

opacity: 0;

transition: opacity 0.3s ease;

}

.floating-tabbar.light-mode .floating-tabbar-item::before {

background: rgba(0, 0, 0, 0.1);

}

.floating-tabbar-item:active::before {

opacity: 1;

}

.floating-tabbar-icon {

width: 20px;

height: 20px;

stroke: rgba(255, 255, 255, 0.9);

transition: all 0.3s ease;

}

.floating-tabbar.light-mode .floating-tabbar-icon {

stroke: rgba(0, 0, 0, 0.8);

}

.floating-tabbar-item:active .floating-tabbar-icon {

transform: scale(0.9);

}

.floating-tabbar-label {

font-size: 10px;

color: rgba(255, 255, 255, 0.8);

font-weight: 500;

transition: color 0.3s ease;

}

.floating-tabbar.light-mode .floating-tabbar-label {

color: rgba(0, 0, 0, 0.7);

}

.floating-tabbar-refresh {

display: flex;

align-items: center;

justify-content: center;

width: 44px;

height: 44px;

background: rgba(255, 255, 255, 0.3);

border: 1px solid rgba(255, 255, 255, 0.4);

border-radius: 50%;

cursor: pointer;

transition: all 0.3s ease;

position: relative;

overflow: hidden;

}

.floating-tabbar.light-mode .floating-tabbar-refresh {

background: rgba(0, 0, 0, 0.1);

border: 1px solid rgba(0, 0, 0, 0.2);

}

.floating-tabbar-refresh::before {

content: '';

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

background: rgba(255, 255, 255, 0.2);

border-radius: 50%;

opacity: 0;

transition: opacity 0.3s ease;

}

.floating-tabbar.light-mode .floating-tabbar-refresh::before {

background: rgba(0, 0, 0, 0.1);

}

.floating-tabbar-refresh:active::before {

opacity: 1;

}

.floating-tabbar-refresh:active {

transform: scale(0.95);

}

.floating-tabbar-refresh-icon {

width: 20px;

height: 20px;

stroke: #fff;

stroke-width: 2;

transition: transform 0.6s ease;

}

.floating-tabbar.light-mode .floating-tabbar-refresh-icon {

stroke: #000;

}

.floating-tabbar-refresh.spinning .floating-tabbar-refresh-icon {

transform: rotate(360deg);

}

/* PWA 모바일에서만 표시 */

.pwa-mobile .floating-tabbar {

display: block;

}

/* 매우 작은 화면에서 간격 조정 */

@media (max-width: 400px) {

.floating-tabbar {

padding: 0 8px;

}

.floating-tabbar-item {

padding: 6px 6px;

}

.floating-tabbar-refresh {

width: 40px;

height: 40px;

}

.floating-tabbar-history {

margin-right: 4px;

}

.floating-tabbar-history-btn {

width: 24px;

height: 24px;

}

.floating-tabbar-history-icon {

width: 12px;

height: 12px;

}

}

/* 안전 영역 대응 (iPhone X 이후) */

@supports (bottom: env(safe-area-inset-bottom)) {

.floating-tabbar {

padding-bottom: env(safe-area-inset-bottom);

height: calc(60px + env(safe-area-inset-bottom));

}

body.pwa-mobile {

padding-bottom: calc(60px + env(safe-area-inset-bottom));

}

}

</style>

<!-- 모바일 하단 고정 탭바 -->

<div class="floating-tabbar">

<div class="floating-tabbar-container">

<!-- 히스토리 네비게이션 -->

<div class="floating-tabbar-history">

<button class="floating-tabbar-history-btn" id="historyBack" onclick="goBack()" disabled>

<svg class="floating-tabbar-history-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<polyline points="15,18 9,12 15,6"/>

</svg>

</button>

<button class="floating-tabbar-history-btn" id="historyForward" onclick="goForward()" disabled>

<svg class="floating-tabbar-history-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<polyline points="9,18 15,12 9,6"/>

</svg>

</button>

</div>

<div class="floating-tabbar-menu">

<?php if (isset($is_member) ? $is_member : '') { ?>

<!-- 회원용 탭바 -->

<div><a href="<?php echo G5_URL ?>" class="floating-tabbar-item">

<svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>

<polyline points="9,22 9,12 15,12 15,22"/>

</svg>

<span class="floating-tabbar-label">홈</span>

</a></div>

<div><a href="<?php echo G5_URL ?>/dashboard" class="floating-tabbar-item">

<svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<rect x="3" y="3" width="7" height="7"/>

<rect x="14" y="3" width="7" height="7"/>

<rect x="14" y="14" width="7" height="7"/>

<rect x="3" y="14" width="7" height="7"/>

</svg>

<span class="floating-tabbar-label">대시보드</span>

</a></div>

<div><a href="javascript:void(0);" onclick="toggleFloatingNotification()" class="floating-tabbar-item">

<svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>

<polyline points="22,6 12,13 2,6"/>

</svg>

<span class="floating-tabbar-label">알림</span>

</a></div>

<div><a href="<?php echo G5_URL ?>/rb/home.php?mb_id=<?php echo $member['mb_id'] ?>" class="floating-tabbar-item">

<svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>

<circle cx="12" cy="7" r="4"/>

</svg>

<span class="floating-tabbar-label">마이페이지</span>

</a></div>

<?php } else { ?>

<!-- 비회원용 탭바 -->

<div><a href="<?php echo G5_URL ?>" class="floating-tabbar-item">

<svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>

<polyline points="9,22 9,12 15,12 15,22"/>

</svg>

<span class="floating-tabbar-label">홈</span>

</a></div>

<div><a href="<?php echo G5_BBS_URL ?>/board.php?bo_table=free" class="floating-tabbar-item">

<svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<path d="M3 3h18v18H3zM9 9h6m-6 4h6m-6 4h4"/>

<line x1="9" y1="9" x2="15" y2="9"/>

<line x1="9" y1="13" x2="15" y2="13"/>

<line x1="9" y1="17" x2="13" y2="17"/>

</svg>

<span class="floating-tabbar-label">게시판</span>

</a></div>

<div><a href="<?php echo G5_BBS_URL ?>/board.php?bo_table=notice" class="floating-tabbar-item">

<svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>

<polyline points="14,2 14,8 20,8"/>

<line x1="16" y1="13" x2="8" y2="13"/>

<line x1="16" y1="17" x2="8" y2="17"/>

<polyline points="10,9 9,9 8,9"/>

</svg>

<span class="floating-tabbar-label">공지</span>

</a></div>

<div><a href="<?php echo G5_BBS_URL ?>/login.php" class="floating-tabbar-item">

<svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/>

<polyline points="10,17 15,12 10,7"/>

<line x1="15" y1="12" x2="3" y2="12"/>

</svg>

<span class="floating-tabbar-label">로그인</span>

</a></div>

<?php } ?>

</div>

<button class="floating-tabbar-refresh" onclick="floatingTabbarRefresh()">

<svg class="floating-tabbar-refresh-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">

<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99" />

</svg>

</button>

</div>

</div>

<script>

// 히스토리 네비게이션 함수들

function updateHistoryButtons() {

const backBtn = document.getElementById('historyBack');

const forwardBtn = document.getElementById('historyForward');

const currentIndex = parseInt(sessionStorage.getItem('historyIndex') || '0');

const maxIndex = parseInt(sessionStorage.getItem('maxHistoryIndex') || '0');

backBtn.disabled = currentIndex <= 0;

forwardBtn.disabled = currentIndex >= maxIndex;

}

function goBack() {

if (window.history.length > 1) {

const currentIndex = parseInt(sessionStorage.getItem('historyIndex') || '0');

sessionStorage.setItem('historyIndex', Math.max(0, currentIndex - 1).toString());

window.history.back();

}

}

function goForward() {

const currentIndex = parseInt(sessionStorage.getItem('historyIndex') || '0');

const maxIndex = parseInt(sessionStorage.getItem('maxHistoryIndex') || '0');

if (currentIndex < maxIndex) {

sessionStorage.setItem('historyIndex', (currentIndex + 1).toString());

window.history.forward();

}

}

// 페이지 로드 시 히스토리 인덱스 업데이트

function trackPageNavigation() {

const currentIndex = parseInt(sessionStorage.getItem('historyIndex') || '0');

if (performance.navigation.type === 0) {

const newIndex = currentIndex + 1;

sessionStorage.setItem('historyIndex', newIndex.toString());

sessionStorage.setItem('maxHistoryIndex', newIndex.toString());

}

updateHistoryButtons();

}

// 배경 밝기 감지 및 테마 자동 변경

function detectFloatingTabbarBrightness() {

const tabbar = document.querySelector('.floating-tabbar');

if (!tabbar) return;

const footer = document.querySelector('footer');

if (footer) {

const footerRect = footer.getBoundingClientRect();

const windowHeight = window.innerHeight;

// 푸터가 화면 하단 근처에 있는지 확인

if (footerRect.top < windowHeight) {

tabbar.classList.remove('light-mode');

} else {

tabbar.classList.add('light-mode');

}

} else {

tabbar.classList.add('light-mode');

}

}

// 스크롤 시 배경 감지

let floatingTabbarTicking = false;

function updateFloatingTabbarTheme() {

if (!floatingTabbarTicking) {

requestAnimationFrame(() => {

detectFloatingTabbarBrightness();

floatingTabbarTicking = false;

});

floatingTabbarTicking = true;

}

}

// 새로고침 버튼

function floatingTabbarRefresh() {

const refreshBtn = document.querySelector('.floating-tabbar-refresh');

refreshBtn.classList.add('spinning');

setTimeout(() => {

location.reload();

}, 600);

}

// popstate 이벤트 리스너

window.addEventListener('popstate', function(event) {

setTimeout(updateHistoryButtons, 100);

});

// 초기화

document.addEventListener('DOMContentLoaded', function() {

trackPageNavigation();

window.addEventListener('scroll', updateFloatingTabbarTheme);

window.addEventListener('resize', updateFloatingTabbarTheme);

detectFloatingTabbarBrightness();

updateHistoryButtons();

// 터치 피드백

document.querySelectorAll('.floating-tabbar-item, .floating-tabbar-refresh, .floating-tabbar-history-btn').forEach(element => {

element.addEventListener('touchstart', function() {

if (!this.disabled) {

this.style.transform = 'scale(0.95)';

}

});

element.addEventListener('touchend', function() {

setTimeout(() => {

this.style.transform = '';

}, 150);

});

});

});

</script>




기존 플로팅 툴바를 하단에 고정하고 하단에 60px 여백을 줌


  • 공유링크 복사

    댓글목록

    등록된 댓글이 없습니다.